Browse Source

Merge pull request #77000 from reduz/make-more-base-nodes-thread-safe

Make more base nodes thread safe
Rémi Verschelde 2 years ago
parent
commit
8cfa19a078

+ 30 - 30
core/core_bind.cpp

@@ -1317,11 +1317,11 @@ Variant ClassDB::instantiate(const StringName &p_class) const {
 	}
 	}
 }
 }
 
 
-bool ClassDB::has_signal(StringName p_class, StringName p_signal) const {
+bool ClassDB::class_has_signal(StringName p_class, StringName p_signal) const {
 	return ::ClassDB::has_signal(p_class, p_signal);
 	return ::ClassDB::has_signal(p_class, p_signal);
 }
 }
 
 
-Dictionary ClassDB::get_signal(StringName p_class, StringName p_signal) const {
+Dictionary ClassDB::class_get_signal(StringName p_class, StringName p_signal) const {
 	MethodInfo signal;
 	MethodInfo signal;
 	if (::ClassDB::get_signal(p_class, p_signal, &signal)) {
 	if (::ClassDB::get_signal(p_class, p_signal, &signal)) {
 		return signal.operator Dictionary();
 		return signal.operator Dictionary();
@@ -1330,7 +1330,7 @@ Dictionary ClassDB::get_signal(StringName p_class, StringName p_signal) const {
 	}
 	}
 }
 }
 
 
-TypedArray<Dictionary> ClassDB::get_signal_list(StringName p_class, bool p_no_inheritance) const {
+TypedArray<Dictionary> ClassDB::class_get_signal_list(StringName p_class, bool p_no_inheritance) const {
 	List<MethodInfo> signals;
 	List<MethodInfo> signals;
 	::ClassDB::get_signal_list(p_class, &signals, p_no_inheritance);
 	::ClassDB::get_signal_list(p_class, &signals, p_no_inheritance);
 	TypedArray<Dictionary> ret;
 	TypedArray<Dictionary> ret;
@@ -1342,7 +1342,7 @@ TypedArray<Dictionary> ClassDB::get_signal_list(StringName p_class, bool p_no_in
 	return ret;
 	return ret;
 }
 }
 
 
-TypedArray<Dictionary> ClassDB::get_property_list(StringName p_class, bool p_no_inheritance) const {
+TypedArray<Dictionary> ClassDB::class_get_property_list(StringName p_class, bool p_no_inheritance) const {
 	List<PropertyInfo> plist;
 	List<PropertyInfo> plist;
 	::ClassDB::get_property_list(p_class, &plist, p_no_inheritance);
 	::ClassDB::get_property_list(p_class, &plist, p_no_inheritance);
 	TypedArray<Dictionary> ret;
 	TypedArray<Dictionary> ret;
@@ -1353,13 +1353,13 @@ TypedArray<Dictionary> ClassDB::get_property_list(StringName p_class, bool p_no_
 	return ret;
 	return ret;
 }
 }
 
 
-Variant ClassDB::get_property(Object *p_object, const StringName &p_property) const {
+Variant ClassDB::class_get_property(Object *p_object, const StringName &p_property) const {
 	Variant ret;
 	Variant ret;
 	::ClassDB::get_property(p_object, p_property, ret);
 	::ClassDB::get_property(p_object, p_property, ret);
 	return ret;
 	return ret;
 }
 }
 
 
-Error ClassDB::set_property(Object *p_object, const StringName &p_property, const Variant &p_value) const {
+Error ClassDB::class_set_property(Object *p_object, const StringName &p_property, const Variant &p_value) const {
 	Variant ret;
 	Variant ret;
 	bool valid;
 	bool valid;
 	if (!::ClassDB::set_property(p_object, p_property, p_value, &valid)) {
 	if (!::ClassDB::set_property(p_object, p_property, p_value, &valid)) {
@@ -1370,11 +1370,11 @@ Error ClassDB::set_property(Object *p_object, const StringName &p_property, cons
 	return OK;
 	return OK;
 }
 }
 
 
-bool ClassDB::has_method(StringName p_class, StringName p_method, bool p_no_inheritance) const {
+bool ClassDB::class_has_method(StringName p_class, StringName p_method, bool p_no_inheritance) const {
 	return ::ClassDB::has_method(p_class, p_method, p_no_inheritance);
 	return ::ClassDB::has_method(p_class, p_method, p_no_inheritance);
 }
 }
 
 
-TypedArray<Dictionary> ClassDB::get_method_list(StringName p_class, bool p_no_inheritance) const {
+TypedArray<Dictionary> ClassDB::class_get_method_list(StringName p_class, bool p_no_inheritance) const {
 	List<MethodInfo> methods;
 	List<MethodInfo> methods;
 	::ClassDB::get_method_list(p_class, &methods, p_no_inheritance);
 	::ClassDB::get_method_list(p_class, &methods, p_no_inheritance);
 	TypedArray<Dictionary> ret;
 	TypedArray<Dictionary> ret;
@@ -1392,7 +1392,7 @@ TypedArray<Dictionary> ClassDB::get_method_list(StringName p_class, bool p_no_in
 	return ret;
 	return ret;
 }
 }
 
 
-PackedStringArray ClassDB::get_integer_constant_list(const StringName &p_class, bool p_no_inheritance) const {
+PackedStringArray ClassDB::class_get_integer_constant_list(const StringName &p_class, bool p_no_inheritance) const {
 	List<String> constants;
 	List<String> constants;
 	::ClassDB::get_integer_constant_list(p_class, &constants, p_no_inheritance);
 	::ClassDB::get_integer_constant_list(p_class, &constants, p_no_inheritance);
 
 
@@ -1406,24 +1406,24 @@ PackedStringArray ClassDB::get_integer_constant_list(const StringName &p_class,
 	return ret;
 	return ret;
 }
 }
 
 
-bool ClassDB::has_integer_constant(const StringName &p_class, const StringName &p_name) const {
+bool ClassDB::class_has_integer_constant(const StringName &p_class, const StringName &p_name) const {
 	bool success;
 	bool success;
 	::ClassDB::get_integer_constant(p_class, p_name, &success);
 	::ClassDB::get_integer_constant(p_class, p_name, &success);
 	return success;
 	return success;
 }
 }
 
 
-int64_t ClassDB::get_integer_constant(const StringName &p_class, const StringName &p_name) const {
+int64_t ClassDB::class_get_integer_constant(const StringName &p_class, const StringName &p_name) const {
 	bool found;
 	bool found;
 	int64_t c = ::ClassDB::get_integer_constant(p_class, p_name, &found);
 	int64_t c = ::ClassDB::get_integer_constant(p_class, p_name, &found);
 	ERR_FAIL_COND_V(!found, 0);
 	ERR_FAIL_COND_V(!found, 0);
 	return c;
 	return c;
 }
 }
 
 
-bool ClassDB::has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) const {
+bool ClassDB::class_has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) const {
 	return ::ClassDB::has_enum(p_class, p_name, p_no_inheritance);
 	return ::ClassDB::has_enum(p_class, p_name, p_no_inheritance);
 }
 }
 
 
-PackedStringArray ClassDB::get_enum_list(const StringName &p_class, bool p_no_inheritance) const {
+PackedStringArray ClassDB::class_get_enum_list(const StringName &p_class, bool p_no_inheritance) const {
 	List<StringName> enums;
 	List<StringName> enums;
 	::ClassDB::get_enum_list(p_class, &enums, p_no_inheritance);
 	::ClassDB::get_enum_list(p_class, &enums, p_no_inheritance);
 
 
@@ -1437,7 +1437,7 @@ PackedStringArray ClassDB::get_enum_list(const StringName &p_class, bool p_no_in
 	return ret;
 	return ret;
 }
 }
 
 
-PackedStringArray ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance) const {
+PackedStringArray ClassDB::class_get_enum_constants(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance) const {
 	List<StringName> constants;
 	List<StringName> constants;
 	::ClassDB::get_enum_constants(p_class, p_enum, &constants, p_no_inheritance);
 	::ClassDB::get_enum_constants(p_class, p_enum, &constants, p_no_inheritance);
 
 
@@ -1451,7 +1451,7 @@ PackedStringArray ClassDB::get_enum_constants(const StringName &p_class, const S
 	return ret;
 	return ret;
 }
 }
 
 
-StringName ClassDB::get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) const {
+StringName ClassDB::class_get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) const {
 	return ::ClassDB::get_integer_constant_enum(p_class, p_name, p_no_inheritance);
 	return ::ClassDB::get_integer_constant_enum(p_class, p_name, p_no_inheritance);
 }
 }
 
 
@@ -1468,27 +1468,27 @@ void ClassDB::_bind_methods() {
 	::ClassDB::bind_method(D_METHOD("can_instantiate", "class"), &ClassDB::can_instantiate);
 	::ClassDB::bind_method(D_METHOD("can_instantiate", "class"), &ClassDB::can_instantiate);
 	::ClassDB::bind_method(D_METHOD("instantiate", "class"), &ClassDB::instantiate);
 	::ClassDB::bind_method(D_METHOD("instantiate", "class"), &ClassDB::instantiate);
 
 
-	::ClassDB::bind_method(D_METHOD("class_has_signal", "class", "signal"), &ClassDB::has_signal);
-	::ClassDB::bind_method(D_METHOD("class_get_signal", "class", "signal"), &ClassDB::get_signal);
-	::ClassDB::bind_method(D_METHOD("class_get_signal_list", "class", "no_inheritance"), &ClassDB::get_signal_list, DEFVAL(false));
+	::ClassDB::bind_method(D_METHOD("class_has_signal", "class", "signal"), &ClassDB::class_has_signal);
+	::ClassDB::bind_method(D_METHOD("class_get_signal", "class", "signal"), &ClassDB::class_get_signal);
+	::ClassDB::bind_method(D_METHOD("class_get_signal_list", "class", "no_inheritance"), &ClassDB::class_get_signal_list, DEFVAL(false));
 
 
-	::ClassDB::bind_method(D_METHOD("class_get_property_list", "class", "no_inheritance"), &ClassDB::get_property_list, DEFVAL(false));
-	::ClassDB::bind_method(D_METHOD("class_get_property", "object", "property"), &ClassDB::get_property);
-	::ClassDB::bind_method(D_METHOD("class_set_property", "object", "property", "value"), &ClassDB::set_property);
+	::ClassDB::bind_method(D_METHOD("class_get_property_list", "class", "no_inheritance"), &ClassDB::class_get_property_list, DEFVAL(false));
+	::ClassDB::bind_method(D_METHOD("class_get_property", "object", "property"), &ClassDB::class_get_property);
+	::ClassDB::bind_method(D_METHOD("class_set_property", "object", "property", "value"), &ClassDB::class_set_property);
 
 
-	::ClassDB::bind_method(D_METHOD("class_has_method", "class", "method", "no_inheritance"), &ClassDB::has_method, DEFVAL(false));
+	::ClassDB::bind_method(D_METHOD("class_has_method", "class", "method", "no_inheritance"), &ClassDB::class_has_method, DEFVAL(false));
 
 
-	::ClassDB::bind_method(D_METHOD("class_get_method_list", "class", "no_inheritance"), &ClassDB::get_method_list, DEFVAL(false));
+	::ClassDB::bind_method(D_METHOD("class_get_method_list", "class", "no_inheritance"), &ClassDB::class_get_method_list, DEFVAL(false));
 
 
-	::ClassDB::bind_method(D_METHOD("class_get_integer_constant_list", "class", "no_inheritance"), &ClassDB::get_integer_constant_list, DEFVAL(false));
+	::ClassDB::bind_method(D_METHOD("class_get_integer_constant_list", "class", "no_inheritance"), &ClassDB::class_get_integer_constant_list, DEFVAL(false));
 
 
-	::ClassDB::bind_method(D_METHOD("class_has_integer_constant", "class", "name"), &ClassDB::has_integer_constant);
-	::ClassDB::bind_method(D_METHOD("class_get_integer_constant", "class", "name"), &ClassDB::get_integer_constant);
+	::ClassDB::bind_method(D_METHOD("class_has_integer_constant", "class", "name"), &ClassDB::class_has_integer_constant);
+	::ClassDB::bind_method(D_METHOD("class_get_integer_constant", "class", "name"), &ClassDB::class_get_integer_constant);
 
 
-	::ClassDB::bind_method(D_METHOD("class_has_enum", "class", "name", "no_inheritance"), &ClassDB::has_enum, DEFVAL(false));
-	::ClassDB::bind_method(D_METHOD("class_get_enum_list", "class", "no_inheritance"), &ClassDB::get_enum_list, DEFVAL(false));
-	::ClassDB::bind_method(D_METHOD("class_get_enum_constants", "class", "enum", "no_inheritance"), &ClassDB::get_enum_constants, DEFVAL(false));
-	::ClassDB::bind_method(D_METHOD("class_get_integer_constant_enum", "class", "name", "no_inheritance"), &ClassDB::get_integer_constant_enum, DEFVAL(false));
+	::ClassDB::bind_method(D_METHOD("class_has_enum", "class", "name", "no_inheritance"), &ClassDB::class_has_enum, DEFVAL(false));
+	::ClassDB::bind_method(D_METHOD("class_get_enum_list", "class", "no_inheritance"), &ClassDB::class_get_enum_list, DEFVAL(false));
+	::ClassDB::bind_method(D_METHOD("class_get_enum_constants", "class", "enum", "no_inheritance"), &ClassDB::class_get_enum_constants, DEFVAL(false));
+	::ClassDB::bind_method(D_METHOD("class_get_integer_constant_enum", "class", "name", "no_inheritance"), &ClassDB::class_get_integer_constant_enum, DEFVAL(false));
 
 
 	::ClassDB::bind_method(D_METHOD("is_class_enabled", "class"), &ClassDB::is_class_enabled);
 	::ClassDB::bind_method(D_METHOD("is_class_enabled", "class"), &ClassDB::is_class_enabled);
 }
 }

+ 15 - 15
core/core_bind.h

@@ -424,26 +424,26 @@ public:
 	bool can_instantiate(const StringName &p_class) const;
 	bool can_instantiate(const StringName &p_class) const;
 	Variant instantiate(const StringName &p_class) const;
 	Variant instantiate(const StringName &p_class) const;
 
 
-	bool has_signal(StringName p_class, StringName p_signal) const;
-	Dictionary get_signal(StringName p_class, StringName p_signal) const;
-	TypedArray<Dictionary> get_signal_list(StringName p_class, bool p_no_inheritance = false) const;
+	bool class_has_signal(StringName p_class, StringName p_signal) const;
+	Dictionary class_get_signal(StringName p_class, StringName p_signal) const;
+	TypedArray<Dictionary> class_get_signal_list(StringName p_class, bool p_no_inheritance = false) const;
 
 
-	TypedArray<Dictionary> get_property_list(StringName p_class, bool p_no_inheritance = false) const;
-	Variant get_property(Object *p_object, const StringName &p_property) const;
-	Error set_property(Object *p_object, const StringName &p_property, const Variant &p_value) const;
+	TypedArray<Dictionary> class_get_property_list(StringName p_class, bool p_no_inheritance = false) const;
+	Variant class_get_property(Object *p_object, const StringName &p_property) const;
+	Error class_set_property(Object *p_object, const StringName &p_property, const Variant &p_value) const;
 
 
-	bool has_method(StringName p_class, StringName p_method, bool p_no_inheritance = false) const;
+	bool class_has_method(StringName p_class, StringName p_method, bool p_no_inheritance = false) const;
 
 
-	TypedArray<Dictionary> get_method_list(StringName p_class, bool p_no_inheritance = false) const;
+	TypedArray<Dictionary> class_get_method_list(StringName p_class, bool p_no_inheritance = false) const;
 
 
-	PackedStringArray get_integer_constant_list(const StringName &p_class, bool p_no_inheritance = false) const;
-	bool has_integer_constant(const StringName &p_class, const StringName &p_name) const;
-	int64_t get_integer_constant(const StringName &p_class, const StringName &p_name) const;
+	PackedStringArray class_get_integer_constant_list(const StringName &p_class, bool p_no_inheritance = false) const;
+	bool class_has_integer_constant(const StringName &p_class, const StringName &p_name) const;
+	int64_t class_get_integer_constant(const StringName &p_class, const StringName &p_name) const;
 
 
-	bool has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const;
-	PackedStringArray get_enum_list(const StringName &p_class, bool p_no_inheritance = false) const;
-	PackedStringArray get_enum_constants(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const;
-	StringName get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const;
+	bool class_has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const;
+	PackedStringArray class_get_enum_list(const StringName &p_class, bool p_no_inheritance = false) const;
+	PackedStringArray class_get_enum_constants(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const;
+	StringName class_get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const;
 
 
 	bool is_class_enabled(StringName p_class) const;
 	bool is_class_enabled(StringName p_class) const;
 
 

+ 24 - 17
core/object/object.h

@@ -836,14 +836,21 @@ public:
 
 
 	/* SCRIPT */
 	/* SCRIPT */
 
 
-	void set_script(const Variant &p_script);
-	Variant get_script() const;
+// When in debug, some non-virtual functions can be overridden for multithreaded guards.
+#ifdef DEBUG_ENABLED
+#define MTVIRTUAL virtual
+#else
+#define MTVIRTUAL
+#endif
+
+	MTVIRTUAL void set_script(const Variant &p_script);
+	MTVIRTUAL Variant get_script() const;
 
 
-	bool has_meta(const StringName &p_name) const;
-	void set_meta(const StringName &p_name, const Variant &p_value);
-	void remove_meta(const StringName &p_name);
-	Variant get_meta(const StringName &p_name, const Variant &p_default = Variant()) const;
-	void get_meta_list(List<StringName> *p_list) const;
+	MTVIRTUAL bool has_meta(const StringName &p_name) const;
+	MTVIRTUAL void set_meta(const StringName &p_name, const Variant &p_value);
+	MTVIRTUAL void remove_meta(const StringName &p_name);
+	MTVIRTUAL Variant get_meta(const StringName &p_name, const Variant &p_default = Variant()) const;
+	MTVIRTUAL void get_meta_list(List<StringName> *p_list) const;
 
 
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 	void set_edited(bool p_edited);
 	void set_edited(bool p_edited);
@@ -870,17 +877,17 @@ public:
 		return emit_signalp(p_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
 		return emit_signalp(p_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
 	}
 	}
 
 
-	Error emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount);
-	bool has_signal(const StringName &p_name) const;
-	void get_signal_list(List<MethodInfo> *p_signals) const;
-	void get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const;
-	void get_all_signal_connections(List<Connection> *p_connections) const;
-	int get_persistent_signal_connection_count() const;
-	void get_signals_connected_to_this(List<Connection> *p_connections) const;
+	MTVIRTUAL Error emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount);
+	MTVIRTUAL bool has_signal(const StringName &p_name) const;
+	MTVIRTUAL void get_signal_list(List<MethodInfo> *p_signals) const;
+	MTVIRTUAL void get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const;
+	MTVIRTUAL void get_all_signal_connections(List<Connection> *p_connections) const;
+	MTVIRTUAL int get_persistent_signal_connection_count() const;
+	MTVIRTUAL void get_signals_connected_to_this(List<Connection> *p_connections) const;
 
 
-	Error connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags = 0);
-	void disconnect(const StringName &p_signal, const Callable &p_callable);
-	bool is_connected(const StringName &p_signal, const Callable &p_callable) const;
+	MTVIRTUAL Error connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags = 0);
+	MTVIRTUAL void disconnect(const StringName &p_signal, const Callable &p_callable);
+	MTVIRTUAL bool is_connected(const StringName &p_signal, const Callable &p_callable) const;
 
 
 	template <typename... VarArgs>
 	template <typename... VarArgs>
 	void call_deferred(const StringName &p_name, VarArgs... p_args) {
 	void call_deferred(const StringName &p_name, VarArgs... p_args) {

+ 11 - 0
core/templates/safe_refcount.h

@@ -102,6 +102,17 @@ public:
 		return value.fetch_sub(p_value, std::memory_order_acq_rel) - p_value;
 		return value.fetch_sub(p_value, std::memory_order_acq_rel) - p_value;
 	}
 	}
 
 
+	_ALWAYS_INLINE_ T bit_or(T p_value) {
+		return value.fetch_or(p_value, std::memory_order_acq_rel);
+	}
+	_ALWAYS_INLINE_ T bit_and(T p_value) {
+		return value.fetch_and(p_value, std::memory_order_acq_rel);
+	}
+
+	_ALWAYS_INLINE_ T bit_xor(T p_value) {
+		return value.fetch_xor(p_value, std::memory_order_acq_rel);
+	}
+
 	// Returns the original value instead of the new one
 	// Returns the original value instead of the new one
 	_ALWAYS_INLINE_ T postsub(T p_value) {
 	_ALWAYS_INLINE_ T postsub(T p_value) {
 		return value.fetch_sub(p_value, std::memory_order_acq_rel);
 		return value.fetch_sub(p_value, std::memory_order_acq_rel);

+ 9 - 2
editor/editor_resource_preview.cpp

@@ -158,8 +158,6 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
 		}
 		}
 		r_texture = generated;
 		r_texture = generated;
 
 
-		int small_thumbnail_size = EditorNode::get_singleton()->get_theme_base()->get_theme_icon(SNAME("Object"), SNAME("EditorIcons"))->get_width(); // Kind of a workaround to retrieve the default icon size
-
 		if (preview_generators[i]->can_generate_small_preview()) {
 		if (preview_generators[i]->can_generate_small_preview()) {
 			Ref<Texture2D> generated_small;
 			Ref<Texture2D> generated_small;
 			Dictionary d;
 			Dictionary d;
@@ -340,9 +338,16 @@ void EditorResourcePreview::_thread() {
 	exited.set();
 	exited.set();
 }
 }
 
 
+void EditorResourcePreview::_update_thumbnail_sizes() {
+	if (small_thumbnail_size == -1) {
+		small_thumbnail_size = EditorNode::get_singleton()->get_theme_base()->get_theme_icon(SNAME("Object"), SNAME("EditorIcons"))->get_width(); // Kind of a workaround to retrieve the default icon size
+	}
+}
+
 void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p_res, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata) {
 void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p_res, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata) {
 	ERR_FAIL_NULL(p_receiver);
 	ERR_FAIL_NULL(p_receiver);
 	ERR_FAIL_COND(!p_res.is_valid());
 	ERR_FAIL_COND(!p_res.is_valid());
+	_update_thumbnail_sizes();
 
 
 	{
 	{
 		MutexLock lock(preview_mutex);
 		MutexLock lock(preview_mutex);
@@ -370,6 +375,8 @@ void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p
 }
 }
 
 
 void EditorResourcePreview::queue_resource_preview(const String &p_path, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata) {
 void EditorResourcePreview::queue_resource_preview(const String &p_path, Object *p_receiver, const StringName &p_receiver_func, const Variant &p_userdata) {
+	_update_thumbnail_sizes();
+
 	ERR_FAIL_NULL(p_receiver);
 	ERR_FAIL_NULL(p_receiver);
 	{
 	{
 		MutexLock lock(preview_mutex);
 		MutexLock lock(preview_mutex);

+ 4 - 0
editor/editor_resource_preview.h

@@ -97,6 +97,8 @@ class EditorResourcePreview : public Node {
 	void _preview_ready(const String &p_path, int p_hash, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_small_texture, ObjectID id, const StringName &p_func, const Variant &p_ud, const Dictionary &p_metadata);
 	void _preview_ready(const String &p_path, int p_hash, const Ref<Texture2D> &p_texture, const Ref<Texture2D> &p_small_texture, ObjectID id, const StringName &p_func, const Variant &p_ud, const Dictionary &p_metadata);
 	void _generate_preview(Ref<ImageTexture> &r_texture, Ref<ImageTexture> &r_small_texture, const QueueItem &p_item, const String &cache_base, Dictionary &p_metadata);
 	void _generate_preview(Ref<ImageTexture> &r_texture, Ref<ImageTexture> &r_small_texture, const QueueItem &p_item, const String &cache_base, Dictionary &p_metadata);
 
 
+	int small_thumbnail_size = -1;
+
 	static void _thread_func(void *ud);
 	static void _thread_func(void *ud);
 	void _thread();
 	void _thread();
 	void _iterate();
 	void _iterate();
@@ -106,6 +108,8 @@ class EditorResourcePreview : public Node {
 
 
 	Vector<Ref<EditorResourcePreviewGenerator>> preview_generators;
 	Vector<Ref<EditorResourcePreviewGenerator>> preview_generators;
 
 
+	void _update_thumbnail_sizes();
+
 protected:
 protected:
 	static void _bind_methods();
 	static void _bind_methods();
 
 

+ 49 - 12
scene/2d/node_2d.cpp

@@ -113,11 +113,11 @@ void Node2D::_edit_set_rect(const Rect2 &p_edit_rect) {
 #endif
 #endif
 
 
 void Node2D::_update_xform_values() {
 void Node2D::_update_xform_values() {
-	position = transform.columns[2];
 	rotation = transform.get_rotation();
 	rotation = transform.get_rotation();
-	scale = transform.get_scale();
 	skew = transform.get_skew();
 	skew = transform.get_skew();
-	_xform_dirty = false;
+	position = transform.columns[2];
+	scale = transform.get_scale();
+	xform_dirty.clear();
 }
 }
 
 
 void Node2D::_update_transform() {
 void Node2D::_update_transform() {
@@ -134,6 +134,7 @@ void Node2D::_update_transform() {
 }
 }
 
 
 void Node2D::reparent(Node *p_parent, bool p_keep_global_transform) {
 void Node2D::reparent(Node *p_parent, bool p_keep_global_transform) {
+	ERR_THREAD_GUARD;
 	Transform2D temp = get_global_transform();
 	Transform2D temp = get_global_transform();
 	Node::reparent(p_parent);
 	Node::reparent(p_parent);
 	if (p_keep_global_transform) {
 	if (p_keep_global_transform) {
@@ -142,7 +143,8 @@ void Node2D::reparent(Node *p_parent, bool p_keep_global_transform) {
 }
 }
 
 
 void Node2D::set_position(const Point2 &p_pos) {
 void Node2D::set_position(const Point2 &p_pos) {
-	if (_xform_dirty) {
+	ERR_THREAD_GUARD;
+	if (xform_dirty.is_set()) {
 		const_cast<Node2D *>(this)->_update_xform_values();
 		const_cast<Node2D *>(this)->_update_xform_values();
 	}
 	}
 	position = p_pos;
 	position = p_pos;
@@ -150,7 +152,8 @@ void Node2D::set_position(const Point2 &p_pos) {
 }
 }
 
 
 void Node2D::set_rotation(real_t p_radians) {
 void Node2D::set_rotation(real_t p_radians) {
-	if (_xform_dirty) {
+	ERR_THREAD_GUARD;
+	if (xform_dirty.is_set()) {
 		const_cast<Node2D *>(this)->_update_xform_values();
 		const_cast<Node2D *>(this)->_update_xform_values();
 	}
 	}
 	rotation = p_radians;
 	rotation = p_radians;
@@ -158,11 +161,13 @@ void Node2D::set_rotation(real_t p_radians) {
 }
 }
 
 
 void Node2D::set_rotation_degrees(real_t p_degrees) {
 void Node2D::set_rotation_degrees(real_t p_degrees) {
+	ERR_THREAD_GUARD;
 	set_rotation(Math::deg_to_rad(p_degrees));
 	set_rotation(Math::deg_to_rad(p_degrees));
 }
 }
 
 
 void Node2D::set_skew(real_t p_radians) {
 void Node2D::set_skew(real_t p_radians) {
-	if (_xform_dirty) {
+	ERR_THREAD_GUARD;
+	if (xform_dirty.is_set()) {
 		const_cast<Node2D *>(this)->_update_xform_values();
 		const_cast<Node2D *>(this)->_update_xform_values();
 	}
 	}
 	skew = p_radians;
 	skew = p_radians;
@@ -170,7 +175,8 @@ void Node2D::set_skew(real_t p_radians) {
 }
 }
 
 
 void Node2D::set_scale(const Size2 &p_scale) {
 void Node2D::set_scale(const Size2 &p_scale) {
-	if (_xform_dirty) {
+	ERR_THREAD_GUARD;
+	if (xform_dirty.is_set()) {
 		const_cast<Node2D *>(this)->_update_xform_values();
 		const_cast<Node2D *>(this)->_update_xform_values();
 	}
 	}
 	scale = p_scale;
 	scale = p_scale;
@@ -185,14 +191,17 @@ void Node2D::set_scale(const Size2 &p_scale) {
 }
 }
 
 
 Point2 Node2D::get_position() const {
 Point2 Node2D::get_position() const {
-	if (_xform_dirty) {
+	ERR_READ_THREAD_GUARD_V(Point2());
+	if (xform_dirty.is_set()) {
 		const_cast<Node2D *>(this)->_update_xform_values();
 		const_cast<Node2D *>(this)->_update_xform_values();
 	}
 	}
+
 	return position;
 	return position;
 }
 }
 
 
 real_t Node2D::get_rotation() const {
 real_t Node2D::get_rotation() const {
-	if (_xform_dirty) {
+	ERR_READ_THREAD_GUARD_V(0);
+	if (xform_dirty.is_set()) {
 		const_cast<Node2D *>(this)->_update_xform_values();
 		const_cast<Node2D *>(this)->_update_xform_values();
 	}
 	}
 
 
@@ -200,11 +209,13 @@ real_t Node2D::get_rotation() const {
 }
 }
 
 
 real_t Node2D::get_rotation_degrees() const {
 real_t Node2D::get_rotation_degrees() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	return Math::rad_to_deg(get_rotation());
 	return Math::rad_to_deg(get_rotation());
 }
 }
 
 
 real_t Node2D::get_skew() const {
 real_t Node2D::get_skew() const {
-	if (_xform_dirty) {
+	ERR_READ_THREAD_GUARD_V(0);
+	if (xform_dirty.is_set()) {
 		const_cast<Node2D *>(this)->_update_xform_values();
 		const_cast<Node2D *>(this)->_update_xform_values();
 	}
 	}
 
 
@@ -212,7 +223,8 @@ real_t Node2D::get_skew() const {
 }
 }
 
 
 Size2 Node2D::get_scale() const {
 Size2 Node2D::get_scale() const {
-	if (_xform_dirty) {
+	ERR_READ_THREAD_GUARD_V(Size2());
+	if (xform_dirty.is_set()) {
 		const_cast<Node2D *>(this)->_update_xform_values();
 		const_cast<Node2D *>(this)->_update_xform_values();
 	}
 	}
 
 
@@ -220,26 +232,32 @@ Size2 Node2D::get_scale() const {
 }
 }
 
 
 Transform2D Node2D::get_transform() const {
 Transform2D Node2D::get_transform() const {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
 	return transform;
 	return transform;
 }
 }
 
 
 void Node2D::rotate(real_t p_radians) {
 void Node2D::rotate(real_t p_radians) {
+	ERR_THREAD_GUARD;
 	set_rotation(get_rotation() + p_radians);
 	set_rotation(get_rotation() + p_radians);
 }
 }
 
 
 void Node2D::translate(const Vector2 &p_amount) {
 void Node2D::translate(const Vector2 &p_amount) {
+	ERR_THREAD_GUARD;
 	set_position(get_position() + p_amount);
 	set_position(get_position() + p_amount);
 }
 }
 
 
 void Node2D::global_translate(const Vector2 &p_amount) {
 void Node2D::global_translate(const Vector2 &p_amount) {
+	ERR_THREAD_GUARD;
 	set_global_position(get_global_position() + p_amount);
 	set_global_position(get_global_position() + p_amount);
 }
 }
 
 
 void Node2D::apply_scale(const Size2 &p_amount) {
 void Node2D::apply_scale(const Size2 &p_amount) {
+	ERR_THREAD_GUARD;
 	set_scale(get_scale() * p_amount);
 	set_scale(get_scale() * p_amount);
 }
 }
 
 
 void Node2D::move_x(real_t p_delta, bool p_scaled) {
 void Node2D::move_x(real_t p_delta, bool p_scaled) {
+	ERR_THREAD_GUARD;
 	Transform2D t = get_transform();
 	Transform2D t = get_transform();
 	Vector2 m = t[0];
 	Vector2 m = t[0];
 	if (!p_scaled) {
 	if (!p_scaled) {
@@ -249,6 +267,7 @@ void Node2D::move_x(real_t p_delta, bool p_scaled) {
 }
 }
 
 
 void Node2D::move_y(real_t p_delta, bool p_scaled) {
 void Node2D::move_y(real_t p_delta, bool p_scaled) {
+	ERR_THREAD_GUARD;
 	Transform2D t = get_transform();
 	Transform2D t = get_transform();
 	Vector2 m = t[1];
 	Vector2 m = t[1];
 	if (!p_scaled) {
 	if (!p_scaled) {
@@ -258,10 +277,12 @@ void Node2D::move_y(real_t p_delta, bool p_scaled) {
 }
 }
 
 
 Point2 Node2D::get_global_position() const {
 Point2 Node2D::get_global_position() const {
+	ERR_READ_THREAD_GUARD_V(Point2());
 	return get_global_transform().get_origin();
 	return get_global_transform().get_origin();
 }
 }
 
 
 void Node2D::set_global_position(const Point2 &p_pos) {
 void Node2D::set_global_position(const Point2 &p_pos) {
+	ERR_THREAD_GUARD;
 	CanvasItem *parent = get_parent_item();
 	CanvasItem *parent = get_parent_item();
 	if (parent) {
 	if (parent) {
 		Transform2D inv = parent->get_global_transform().affine_inverse();
 		Transform2D inv = parent->get_global_transform().affine_inverse();
@@ -272,18 +293,22 @@ void Node2D::set_global_position(const Point2 &p_pos) {
 }
 }
 
 
 real_t Node2D::get_global_rotation() const {
 real_t Node2D::get_global_rotation() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	return get_global_transform().get_rotation();
 	return get_global_transform().get_rotation();
 }
 }
 
 
 real_t Node2D::get_global_rotation_degrees() const {
 real_t Node2D::get_global_rotation_degrees() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	return Math::rad_to_deg(get_global_rotation());
 	return Math::rad_to_deg(get_global_rotation());
 }
 }
 
 
 real_t Node2D::get_global_skew() const {
 real_t Node2D::get_global_skew() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	return get_global_transform().get_skew();
 	return get_global_transform().get_skew();
 }
 }
 
 
 void Node2D::set_global_rotation(const real_t p_radians) {
 void Node2D::set_global_rotation(const real_t p_radians) {
+	ERR_THREAD_GUARD;
 	CanvasItem *parent = get_parent_item();
 	CanvasItem *parent = get_parent_item();
 	if (parent) {
 	if (parent) {
 		Transform2D parent_global_transform = parent->get_global_transform();
 		Transform2D parent_global_transform = parent->get_global_transform();
@@ -297,10 +322,12 @@ void Node2D::set_global_rotation(const real_t p_radians) {
 }
 }
 
 
 void Node2D::set_global_rotation_degrees(const real_t p_degrees) {
 void Node2D::set_global_rotation_degrees(const real_t p_degrees) {
+	ERR_THREAD_GUARD;
 	set_global_rotation(Math::deg_to_rad(p_degrees));
 	set_global_rotation(Math::deg_to_rad(p_degrees));
 }
 }
 
 
 void Node2D::set_global_skew(const real_t p_radians) {
 void Node2D::set_global_skew(const real_t p_radians) {
+	ERR_THREAD_GUARD;
 	CanvasItem *parent = get_parent_item();
 	CanvasItem *parent = get_parent_item();
 	if (parent) {
 	if (parent) {
 		Transform2D parent_global_transform = parent->get_global_transform();
 		Transform2D parent_global_transform = parent->get_global_transform();
@@ -314,10 +341,12 @@ void Node2D::set_global_skew(const real_t p_radians) {
 }
 }
 
 
 Size2 Node2D::get_global_scale() const {
 Size2 Node2D::get_global_scale() const {
+	ERR_READ_THREAD_GUARD_V(Size2());
 	return get_global_transform().get_scale();
 	return get_global_transform().get_scale();
 }
 }
 
 
 void Node2D::set_global_scale(const Size2 &p_scale) {
 void Node2D::set_global_scale(const Size2 &p_scale) {
+	ERR_THREAD_GUARD;
 	CanvasItem *parent = get_parent_item();
 	CanvasItem *parent = get_parent_item();
 	if (parent) {
 	if (parent) {
 		Transform2D parent_global_transform = parent->get_global_transform();
 		Transform2D parent_global_transform = parent->get_global_transform();
@@ -331,8 +360,9 @@ void Node2D::set_global_scale(const Size2 &p_scale) {
 }
 }
 
 
 void Node2D::set_transform(const Transform2D &p_transform) {
 void Node2D::set_transform(const Transform2D &p_transform) {
+	ERR_THREAD_GUARD;
 	transform = p_transform;
 	transform = p_transform;
-	_xform_dirty = true;
+	xform_dirty.set();
 
 
 	RenderingServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), transform);
 	RenderingServer::get_singleton()->canvas_item_set_transform(get_canvas_item(), transform);
 
 
@@ -344,6 +374,7 @@ void Node2D::set_transform(const Transform2D &p_transform) {
 }
 }
 
 
 void Node2D::set_global_transform(const Transform2D &p_transform) {
 void Node2D::set_global_transform(const Transform2D &p_transform) {
+	ERR_THREAD_GUARD;
 	CanvasItem *parent = get_parent_item();
 	CanvasItem *parent = get_parent_item();
 	if (parent) {
 	if (parent) {
 		set_transform(parent->get_global_transform().affine_inverse() * p_transform);
 		set_transform(parent->get_global_transform().affine_inverse() * p_transform);
@@ -353,6 +384,7 @@ void Node2D::set_global_transform(const Transform2D &p_transform) {
 }
 }
 
 
 Transform2D Node2D::get_relative_transform_to_parent(const Node *p_parent) const {
 Transform2D Node2D::get_relative_transform_to_parent(const Node *p_parent) const {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
 	if (p_parent == this) {
 	if (p_parent == this) {
 		return Transform2D();
 		return Transform2D();
 	}
 	}
@@ -368,22 +400,27 @@ Transform2D Node2D::get_relative_transform_to_parent(const Node *p_parent) const
 }
 }
 
 
 void Node2D::look_at(const Vector2 &p_pos) {
 void Node2D::look_at(const Vector2 &p_pos) {
+	ERR_THREAD_GUARD;
 	rotate(get_angle_to(p_pos));
 	rotate(get_angle_to(p_pos));
 }
 }
 
 
 real_t Node2D::get_angle_to(const Vector2 &p_pos) const {
 real_t Node2D::get_angle_to(const Vector2 &p_pos) const {
+	ERR_READ_THREAD_GUARD_V(0);
 	return (to_local(p_pos) * get_scale()).angle();
 	return (to_local(p_pos) * get_scale()).angle();
 }
 }
 
 
 Point2 Node2D::to_local(Point2 p_global) const {
 Point2 Node2D::to_local(Point2 p_global) const {
+	ERR_READ_THREAD_GUARD_V(Point2());
 	return get_global_transform().affine_inverse().xform(p_global);
 	return get_global_transform().affine_inverse().xform(p_global);
 }
 }
 
 
 Point2 Node2D::to_global(Point2 p_local) const {
 Point2 Node2D::to_global(Point2 p_local) const {
+	ERR_READ_THREAD_GUARD_V(Point2());
 	return get_global_transform().xform(p_local);
 	return get_global_transform().xform(p_local);
 }
 }
 
 
 void Node2D::_notification(int p_notification) {
 void Node2D::_notification(int p_notification) {
+	ERR_THREAD_GUARD;
 	switch (p_notification) {
 	switch (p_notification) {
 		case NOTIFICATION_ENTER_TREE: {
 		case NOTIFICATION_ENTER_TREE: {
 			if (get_viewport()) {
 			if (get_viewport()) {

+ 1 - 2
scene/2d/node_2d.h

@@ -36,6 +36,7 @@
 class Node2D : public CanvasItem {
 class Node2D : public CanvasItem {
 	GDCLASS(Node2D, CanvasItem);
 	GDCLASS(Node2D, CanvasItem);
 
 
+	SafeFlag xform_dirty;
 	Point2 position;
 	Point2 position;
 	real_t rotation = 0.0;
 	real_t rotation = 0.0;
 	Size2 scale = Vector2(1, 1);
 	Size2 scale = Vector2(1, 1);
@@ -43,8 +44,6 @@ class Node2D : public CanvasItem {
 
 
 	Transform2D transform;
 	Transform2D transform;
 
 
-	bool _xform_dirty = false;
-
 	void _update_transform();
 	void _update_transform();
 
 
 	void _update_xform_values();
 	void _update_xform_values();

+ 127 - 42
scene/3d/node_3d.cpp

@@ -86,10 +86,8 @@ void Node3D::_notify_dirty() {
 
 
 void Node3D::_update_local_transform() const {
 void Node3D::_update_local_transform() const {
 	// This function is called when the local transform (data.local_transform) is dirty and the right value is contained in the Euler rotation and scale.
 	// This function is called when the local transform (data.local_transform) is dirty and the right value is contained in the Euler rotation and scale.
-
 	data.local_transform.basis.set_euler_scale(data.euler_rotation, data.scale, data.euler_rotation_order);
 	data.local_transform.basis.set_euler_scale(data.euler_rotation, data.scale, data.euler_rotation_order);
-
-	data.dirty &= ~DIRTY_LOCAL_TRANSFORM;
+	data.dirty.bit_and(~DIRTY_LOCAL_TRANSFORM);
 }
 }
 
 
 void Node3D::_update_rotation_and_scale() const {
 void Node3D::_update_rotation_and_scale() const {
@@ -97,8 +95,13 @@ void Node3D::_update_rotation_and_scale() const {
 
 
 	data.scale = data.local_transform.basis.get_scale();
 	data.scale = data.local_transform.basis.get_scale();
 	data.euler_rotation = data.local_transform.basis.get_euler_normalized(data.euler_rotation_order);
 	data.euler_rotation = data.local_transform.basis.get_euler_normalized(data.euler_rotation_order);
+	data.dirty.bit_and(~DIRTY_EULER_ROTATION_AND_SCALE);
+}
 
 
-	data.dirty &= ~DIRTY_EULER_ROTATION_AND_SCALE;
+void Node3D::_propagate_transform_changed_deferred() {
+	if (is_inside_tree() && !xform_change.in_list()) {
+		get_tree()->xform_change_list.add(&xform_change);
+	}
 }
 }
 
 
 void Node3D::_propagate_transform_changed(Node3D *p_origin) {
 void Node3D::_propagate_transform_changed(Node3D *p_origin) {
@@ -106,8 +109,6 @@ void Node3D::_propagate_transform_changed(Node3D *p_origin) {
 		return;
 		return;
 	}
 	}
 
 
-	data.children_lock++;
-
 	for (Node3D *&E : data.children) {
 	for (Node3D *&E : data.children) {
 		if (E->data.top_level_active) {
 		if (E->data.top_level_active) {
 			continue; //don't propagate to a top_level
 			continue; //don't propagate to a top_level
@@ -119,14 +120,19 @@ void Node3D::_propagate_transform_changed(Node3D *p_origin) {
 #else
 #else
 	if (data.notify_transform && !data.ignore_notification && !xform_change.in_list()) {
 	if (data.notify_transform && !data.ignore_notification && !xform_change.in_list()) {
 #endif
 #endif
-		get_tree()->xform_change_list.add(&xform_change);
+		if (likely(is_accessible_from_caller_thread())) {
+			get_tree()->xform_change_list.add(&xform_change);
+		} else {
+			// This should very rarely happen, but if it does at least make sure the notification is received eventually.
+			MessageQueue::get_singleton()->push_callable(callable_mp(this, &Node3D::_propagate_transform_changed_deferred));
+		}
 	}
 	}
-	data.dirty |= DIRTY_GLOBAL_TRANSFORM;
-
-	data.children_lock--;
+	data.dirty.bit_or(DIRTY_GLOBAL_TRANSFORM);
 }
 }
 
 
 void Node3D::_notification(int p_what) {
 void Node3D::_notification(int p_what) {
+	ERR_THREAD_GUARD;
+
 	switch (p_what) {
 	switch (p_what) {
 		case NOTIFICATION_ENTER_TREE: {
 		case NOTIFICATION_ENTER_TREE: {
 			ERR_FAIL_COND(!get_tree());
 			ERR_FAIL_COND(!get_tree());
@@ -145,12 +151,12 @@ void Node3D::_notification(int p_what) {
 			if (data.top_level && !Engine::get_singleton()->is_editor_hint()) {
 			if (data.top_level && !Engine::get_singleton()->is_editor_hint()) {
 				if (data.parent) {
 				if (data.parent) {
 					data.local_transform = data.parent->get_global_transform() * get_transform();
 					data.local_transform = data.parent->get_global_transform() * get_transform();
-					data.dirty = DIRTY_EULER_ROTATION_AND_SCALE; // As local transform was updated, rot/scale should be dirty.
+					data.dirty.set(DIRTY_EULER_ROTATION_AND_SCALE); // As local transform was updated, rot/scale should be dirty.
 				}
 				}
 				data.top_level_active = true;
 				data.top_level_active = true;
 			}
 			}
 
 
-			data.dirty |= DIRTY_GLOBAL_TRANSFORM; // Global is always dirty upon entering a scene.
+			data.dirty.bit_or(DIRTY_GLOBAL_TRANSFORM); // Global is always dirty upon entering a scene.
 			_notify_dirty();
 			_notify_dirty();
 
 
 			notification(NOTIFICATION_ENTER_WORLD);
 			notification(NOTIFICATION_ENTER_WORLD);
@@ -217,19 +223,23 @@ void Node3D::_notification(int p_what) {
 }
 }
 
 
 void Node3D::set_basis(const Basis &p_basis) {
 void Node3D::set_basis(const Basis &p_basis) {
+	ERR_THREAD_GUARD;
+
 	set_transform(Transform3D(p_basis, data.local_transform.origin));
 	set_transform(Transform3D(p_basis, data.local_transform.origin));
 }
 }
 void Node3D::set_quaternion(const Quaternion &p_quaternion) {
 void Node3D::set_quaternion(const Quaternion &p_quaternion) {
-	if (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE) {
+	ERR_THREAD_GUARD;
+
+	if (data.dirty.get() & DIRTY_EULER_ROTATION_AND_SCALE) {
 		// We need the scale part, so if these are dirty, update it
 		// We need the scale part, so if these are dirty, update it
 		data.scale = data.local_transform.basis.get_scale();
 		data.scale = data.local_transform.basis.get_scale();
-		data.dirty &= ~DIRTY_EULER_ROTATION_AND_SCALE;
+		data.dirty.bit_and(~DIRTY_EULER_ROTATION_AND_SCALE);
 	}
 	}
 	data.local_transform.basis = Basis(p_quaternion, data.scale);
 	data.local_transform.basis = Basis(p_quaternion, data.scale);
 	// Rotscale should not be marked dirty because that would cause precision loss issues with the scale. Instead reconstruct rotation now.
 	// Rotscale should not be marked dirty because that would cause precision loss issues with the scale. Instead reconstruct rotation now.
 	data.euler_rotation = data.local_transform.basis.get_euler_normalized(data.euler_rotation_order);
 	data.euler_rotation = data.local_transform.basis.get_euler_normalized(data.euler_rotation_order);
 
 
-	data.dirty = DIRTY_NONE;
+	data.dirty.set(DIRTY_NONE);
 
 
 	_propagate_transform_changed(this);
 	_propagate_transform_changed(this);
 	if (data.notify_local_transform) {
 	if (data.notify_local_transform) {
@@ -238,38 +248,45 @@ void Node3D::set_quaternion(const Quaternion &p_quaternion) {
 }
 }
 
 
 Vector3 Node3D::get_global_position() const {
 Vector3 Node3D::get_global_position() const {
+	ERR_READ_THREAD_GUARD_V(Vector3());
 	return get_global_transform().get_origin();
 	return get_global_transform().get_origin();
 }
 }
 
 
 void Node3D::set_global_position(const Vector3 &p_position) {
 void Node3D::set_global_position(const Vector3 &p_position) {
+	ERR_THREAD_GUARD;
 	Transform3D transform = get_global_transform();
 	Transform3D transform = get_global_transform();
 	transform.set_origin(p_position);
 	transform.set_origin(p_position);
 	set_global_transform(transform);
 	set_global_transform(transform);
 }
 }
 
 
 Vector3 Node3D::get_global_rotation() const {
 Vector3 Node3D::get_global_rotation() const {
+	ERR_READ_THREAD_GUARD_V(Vector3());
 	return get_global_transform().get_basis().get_euler();
 	return get_global_transform().get_basis().get_euler();
 }
 }
 
 
 Vector3 Node3D::get_global_rotation_degrees() const {
 Vector3 Node3D::get_global_rotation_degrees() const {
+	ERR_READ_THREAD_GUARD_V(Vector3());
 	Vector3 radians = get_global_rotation();
 	Vector3 radians = get_global_rotation();
 	return Vector3(Math::rad_to_deg(radians.x), Math::rad_to_deg(radians.y), Math::rad_to_deg(radians.z));
 	return Vector3(Math::rad_to_deg(radians.x), Math::rad_to_deg(radians.y), Math::rad_to_deg(radians.z));
 }
 }
 
 
 void Node3D::set_global_rotation(const Vector3 &p_euler_rad) {
 void Node3D::set_global_rotation(const Vector3 &p_euler_rad) {
+	ERR_THREAD_GUARD;
 	Transform3D transform = get_global_transform();
 	Transform3D transform = get_global_transform();
 	transform.basis = Basis::from_euler(p_euler_rad);
 	transform.basis = Basis::from_euler(p_euler_rad);
 	set_global_transform(transform);
 	set_global_transform(transform);
 }
 }
 
 
 void Node3D::set_global_rotation_degrees(const Vector3 &p_euler_degrees) {
 void Node3D::set_global_rotation_degrees(const Vector3 &p_euler_degrees) {
+	ERR_THREAD_GUARD;
 	Vector3 radians(Math::deg_to_rad(p_euler_degrees.x), Math::deg_to_rad(p_euler_degrees.y), Math::deg_to_rad(p_euler_degrees.z));
 	Vector3 radians(Math::deg_to_rad(p_euler_degrees.x), Math::deg_to_rad(p_euler_degrees.y), Math::deg_to_rad(p_euler_degrees.z));
 	set_global_rotation(radians);
 	set_global_rotation(radians);
 }
 }
 
 
 void Node3D::set_transform(const Transform3D &p_transform) {
 void Node3D::set_transform(const Transform3D &p_transform) {
+	ERR_THREAD_GUARD;
 	data.local_transform = p_transform;
 	data.local_transform = p_transform;
-	data.dirty = DIRTY_EULER_ROTATION_AND_SCALE; // Make rot/scale dirty.
+	data.dirty.set(DIRTY_EULER_ROTATION_AND_SCALE); // Make rot/scale dirty.
 
 
 	_propagate_transform_changed(this);
 	_propagate_transform_changed(this);
 	if (data.notify_local_transform) {
 	if (data.notify_local_transform) {
@@ -278,18 +295,16 @@ void Node3D::set_transform(const Transform3D &p_transform) {
 }
 }
 
 
 Basis Node3D::get_basis() const {
 Basis Node3D::get_basis() const {
+	ERR_READ_THREAD_GUARD_V(Basis());
 	return get_transform().basis;
 	return get_transform().basis;
 }
 }
 
 
 Quaternion Node3D::get_quaternion() const {
 Quaternion Node3D::get_quaternion() const {
-	if (data.dirty & DIRTY_LOCAL_TRANSFORM) {
-		_update_local_transform();
-	}
-
-	return data.local_transform.basis.get_rotation_quaternion();
+	return get_transform().basis.get_rotation_quaternion();
 }
 }
 
 
 void Node3D::set_global_transform(const Transform3D &p_transform) {
 void Node3D::set_global_transform(const Transform3D &p_transform) {
+	ERR_THREAD_GUARD;
 	Transform3D xform = (data.parent && !data.top_level_active)
 	Transform3D xform = (data.parent && !data.top_level_active)
 			? data.parent->get_global_transform().affine_inverse() * p_transform
 			? data.parent->get_global_transform().affine_inverse() * p_transform
 			: p_transform;
 			: p_transform;
@@ -298,31 +313,42 @@ void Node3D::set_global_transform(const Transform3D &p_transform) {
 }
 }
 
 
 Transform3D Node3D::get_transform() const {
 Transform3D Node3D::get_transform() const {
-	if (data.dirty & DIRTY_LOCAL_TRANSFORM) {
+	ERR_READ_THREAD_GUARD_V(Transform3D());
+	if (data.dirty.get() & DIRTY_LOCAL_TRANSFORM) {
+		// This update can happen if needed over multiple threads.
 		_update_local_transform();
 		_update_local_transform();
 	}
 	}
 
 
 	return data.local_transform;
 	return data.local_transform;
 }
 }
+
 Transform3D Node3D::get_global_transform() const {
 Transform3D Node3D::get_global_transform() const {
 	ERR_FAIL_COND_V(!is_inside_tree(), Transform3D());
 	ERR_FAIL_COND_V(!is_inside_tree(), Transform3D());
 
 
-	if (data.dirty & DIRTY_GLOBAL_TRANSFORM) {
-		if (data.dirty & DIRTY_LOCAL_TRANSFORM) {
-			_update_local_transform();
+	/* Due to how threads work at scene level, while this global transform won't be able to be changed from outside a thread,
+	 * it is possible that multiple threads can access it while it's dirty from previous work. Due to this, we must ensure that
+	 * the dirty/update process is thread safe by utilizing atomic copies.
+	 */
+
+	uint32_t dirty = data.dirty.get();
+	if (dirty & DIRTY_GLOBAL_TRANSFORM) {
+		if (dirty & DIRTY_LOCAL_TRANSFORM) {
+			_update_local_transform(); // Update local transform atomically.
 		}
 		}
 
 
+		Transform3D new_global;
 		if (data.parent && !data.top_level_active) {
 		if (data.parent && !data.top_level_active) {
-			data.global_transform = data.parent->get_global_transform() * data.local_transform;
+			new_global = data.parent->get_global_transform() * data.local_transform;
 		} else {
 		} else {
-			data.global_transform = data.local_transform;
+			new_global = data.local_transform;
 		}
 		}
 
 
 		if (data.disable_scale) {
 		if (data.disable_scale) {
-			data.global_transform.basis.orthonormalize();
+			new_global.basis.orthonormalize();
 		}
 		}
 
 
-		data.dirty &= ~DIRTY_GLOBAL_TRANSFORM;
+		data.global_transform = new_global;
+		data.dirty.bit_and(~DIRTY_GLOBAL_TRANSFORM);
 	}
 	}
 
 
 	return data.global_transform;
 	return data.global_transform;
@@ -339,6 +365,7 @@ Transform3D Node3D::get_local_gizmo_transform() const {
 #endif
 #endif
 
 
 Node3D *Node3D::get_parent_node_3d() const {
 Node3D *Node3D::get_parent_node_3d() const {
+	ERR_READ_THREAD_GUARD_V(nullptr); // This can't be changed on threads anyway.
 	if (data.top_level) {
 	if (data.top_level) {
 		return nullptr;
 		return nullptr;
 	}
 	}
@@ -347,6 +374,7 @@ Node3D *Node3D::get_parent_node_3d() const {
 }
 }
 
 
 Transform3D Node3D::get_relative_transform(const Node *p_parent) const {
 Transform3D Node3D::get_relative_transform(const Node *p_parent) const {
+	ERR_READ_THREAD_GUARD_V(Transform3D());
 	if (p_parent == this) {
 	if (p_parent == this) {
 		return Transform3D();
 		return Transform3D();
 	}
 	}
@@ -361,6 +389,7 @@ Transform3D Node3D::get_relative_transform(const Node *p_parent) const {
 }
 }
 
 
 void Node3D::set_position(const Vector3 &p_position) {
 void Node3D::set_position(const Vector3 &p_position) {
+	ERR_THREAD_GUARD;
 	data.local_transform.origin = p_position;
 	data.local_transform.origin = p_position;
 	_propagate_transform_changed(this);
 	_propagate_transform_changed(this);
 	if (data.notify_local_transform) {
 	if (data.notify_local_transform) {
@@ -369,19 +398,20 @@ void Node3D::set_position(const Vector3 &p_position) {
 }
 }
 
 
 void Node3D::set_rotation_edit_mode(RotationEditMode p_mode) {
 void Node3D::set_rotation_edit_mode(RotationEditMode p_mode) {
+	ERR_THREAD_GUARD;
 	if (data.rotation_edit_mode == p_mode) {
 	if (data.rotation_edit_mode == p_mode) {
 		return;
 		return;
 	}
 	}
 
 
 	bool transform_changed = false;
 	bool transform_changed = false;
-	if (data.rotation_edit_mode == ROTATION_EDIT_MODE_BASIS && !(data.dirty & DIRTY_LOCAL_TRANSFORM)) {
+	if (data.rotation_edit_mode == ROTATION_EDIT_MODE_BASIS && !(data.dirty.get() & DIRTY_LOCAL_TRANSFORM)) {
 		data.local_transform.orthogonalize();
 		data.local_transform.orthogonalize();
 		transform_changed = true;
 		transform_changed = true;
 	}
 	}
 
 
 	data.rotation_edit_mode = p_mode;
 	data.rotation_edit_mode = p_mode;
 
 
-	if (p_mode == ROTATION_EDIT_MODE_EULER && (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE)) {
+	if (p_mode == ROTATION_EDIT_MODE_EULER && (data.dirty.get() & DIRTY_EULER_ROTATION_AND_SCALE)) {
 		// If going to Euler mode, ensure that vectors are _not_ dirty, else the retrieved value may be wrong.
 		// If going to Euler mode, ensure that vectors are _not_ dirty, else the retrieved value may be wrong.
 		// Otherwise keep what is there, so switching back and forth between modes does not break the vectors.
 		// Otherwise keep what is there, so switching back and forth between modes does not break the vectors.
 
 
@@ -399,10 +429,12 @@ void Node3D::set_rotation_edit_mode(RotationEditMode p_mode) {
 }
 }
 
 
 Node3D::RotationEditMode Node3D::get_rotation_edit_mode() const {
 Node3D::RotationEditMode Node3D::get_rotation_edit_mode() const {
+	ERR_READ_THREAD_GUARD_V(ROTATION_EDIT_MODE_EULER);
 	return data.rotation_edit_mode;
 	return data.rotation_edit_mode;
 }
 }
 
 
 void Node3D::set_rotation_order(EulerOrder p_order) {
 void Node3D::set_rotation_order(EulerOrder p_order) {
+	ERR_THREAD_GUARD;
 	if (data.euler_rotation_order == p_order) {
 	if (data.euler_rotation_order == p_order) {
 		return;
 		return;
 	}
 	}
@@ -410,13 +442,13 @@ void Node3D::set_rotation_order(EulerOrder p_order) {
 	ERR_FAIL_INDEX(int32_t(p_order), 6);
 	ERR_FAIL_INDEX(int32_t(p_order), 6);
 	bool transform_changed = false;
 	bool transform_changed = false;
 
 
-	if (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE) {
+	if (data.dirty.get() & DIRTY_EULER_ROTATION_AND_SCALE) {
 		_update_rotation_and_scale();
 		_update_rotation_and_scale();
-	} else if (data.dirty & DIRTY_LOCAL_TRANSFORM) {
+	} else if (data.dirty.get() & DIRTY_LOCAL_TRANSFORM) {
 		data.euler_rotation = Basis::from_euler(data.euler_rotation, data.euler_rotation_order).get_euler_normalized(p_order);
 		data.euler_rotation = Basis::from_euler(data.euler_rotation, data.euler_rotation_order).get_euler_normalized(p_order);
 		transform_changed = true;
 		transform_changed = true;
 	} else {
 	} else {
-		data.dirty |= DIRTY_LOCAL_TRANSFORM;
+		data.dirty.bit_or(DIRTY_LOCAL_TRANSFORM);
 		transform_changed = true;
 		transform_changed = true;
 	}
 	}
 
 
@@ -432,18 +464,20 @@ void Node3D::set_rotation_order(EulerOrder p_order) {
 }
 }
 
 
 EulerOrder Node3D::get_rotation_order() const {
 EulerOrder Node3D::get_rotation_order() const {
+	ERR_READ_THREAD_GUARD_V(EulerOrder::XYZ);
 	return data.euler_rotation_order;
 	return data.euler_rotation_order;
 }
 }
 
 
 void Node3D::set_rotation(const Vector3 &p_euler_rad) {
 void Node3D::set_rotation(const Vector3 &p_euler_rad) {
-	if (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE) {
+	ERR_THREAD_GUARD;
+	if (data.dirty.get() & DIRTY_EULER_ROTATION_AND_SCALE) {
 		// Update scale only if rotation and scale are dirty, as rotation will be overridden.
 		// Update scale only if rotation and scale are dirty, as rotation will be overridden.
 		data.scale = data.local_transform.basis.get_scale();
 		data.scale = data.local_transform.basis.get_scale();
-		data.dirty &= ~DIRTY_EULER_ROTATION_AND_SCALE;
+		data.dirty.bit_and(~DIRTY_EULER_ROTATION_AND_SCALE);
 	}
 	}
 
 
 	data.euler_rotation = p_euler_rad;
 	data.euler_rotation = p_euler_rad;
-	data.dirty = DIRTY_LOCAL_TRANSFORM;
+	data.dirty.set(DIRTY_LOCAL_TRANSFORM);
 	_propagate_transform_changed(this);
 	_propagate_transform_changed(this);
 	if (data.notify_local_transform) {
 	if (data.notify_local_transform) {
 		notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
 		notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
@@ -451,19 +485,21 @@ void Node3D::set_rotation(const Vector3 &p_euler_rad) {
 }
 }
 
 
 void Node3D::set_rotation_degrees(const Vector3 &p_euler_degrees) {
 void Node3D::set_rotation_degrees(const Vector3 &p_euler_degrees) {
+	ERR_THREAD_GUARD;
 	Vector3 radians(Math::deg_to_rad(p_euler_degrees.x), Math::deg_to_rad(p_euler_degrees.y), Math::deg_to_rad(p_euler_degrees.z));
 	Vector3 radians(Math::deg_to_rad(p_euler_degrees.x), Math::deg_to_rad(p_euler_degrees.y), Math::deg_to_rad(p_euler_degrees.z));
 	set_rotation(radians);
 	set_rotation(radians);
 }
 }
 
 
 void Node3D::set_scale(const Vector3 &p_scale) {
 void Node3D::set_scale(const Vector3 &p_scale) {
-	if (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE) {
+	ERR_THREAD_GUARD;
+	if (data.dirty.get() & DIRTY_EULER_ROTATION_AND_SCALE) {
 		// Update rotation only if rotation and scale are dirty, as scale will be overridden.
 		// Update rotation only if rotation and scale are dirty, as scale will be overridden.
 		data.euler_rotation = data.local_transform.basis.get_euler_normalized(data.euler_rotation_order);
 		data.euler_rotation = data.local_transform.basis.get_euler_normalized(data.euler_rotation_order);
-		data.dirty &= ~DIRTY_EULER_ROTATION_AND_SCALE;
+		data.dirty.bit_and(~DIRTY_EULER_ROTATION_AND_SCALE);
 	}
 	}
 
 
 	data.scale = p_scale;
 	data.scale = p_scale;
-	data.dirty = DIRTY_LOCAL_TRANSFORM;
+	data.dirty.set(DIRTY_LOCAL_TRANSFORM);
 	_propagate_transform_changed(this);
 	_propagate_transform_changed(this);
 	if (data.notify_local_transform) {
 	if (data.notify_local_transform) {
 		notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
 		notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
@@ -471,11 +507,13 @@ void Node3D::set_scale(const Vector3 &p_scale) {
 }
 }
 
 
 Vector3 Node3D::get_position() const {
 Vector3 Node3D::get_position() const {
+	ERR_READ_THREAD_GUARD_V(Vector3());
 	return data.local_transform.origin;
 	return data.local_transform.origin;
 }
 }
 
 
 Vector3 Node3D::get_rotation() const {
 Vector3 Node3D::get_rotation() const {
-	if (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE) {
+	ERR_READ_THREAD_GUARD_V(Vector3());
+	if (data.dirty.get() & DIRTY_EULER_ROTATION_AND_SCALE) {
 		_update_rotation_and_scale();
 		_update_rotation_and_scale();
 	}
 	}
 
 
@@ -483,12 +521,14 @@ Vector3 Node3D::get_rotation() const {
 }
 }
 
 
 Vector3 Node3D::get_rotation_degrees() const {
 Vector3 Node3D::get_rotation_degrees() const {
+	ERR_READ_THREAD_GUARD_V(Vector3());
 	Vector3 radians = get_rotation();
 	Vector3 radians = get_rotation();
 	return Vector3(Math::rad_to_deg(radians.x), Math::rad_to_deg(radians.y), Math::rad_to_deg(radians.z));
 	return Vector3(Math::rad_to_deg(radians.x), Math::rad_to_deg(radians.y), Math::rad_to_deg(radians.z));
 }
 }
 
 
 Vector3 Node3D::get_scale() const {
 Vector3 Node3D::get_scale() const {
-	if (data.dirty & DIRTY_EULER_ROTATION_AND_SCALE) {
+	ERR_READ_THREAD_GUARD_V(Vector3());
+	if (data.dirty.get() & DIRTY_EULER_ROTATION_AND_SCALE) {
 		_update_rotation_and_scale();
 		_update_rotation_and_scale();
 	}
 	}
 
 
@@ -496,6 +536,7 @@ Vector3 Node3D::get_scale() const {
 }
 }
 
 
 void Node3D::update_gizmos() {
 void Node3D::update_gizmos() {
+	ERR_THREAD_GUARD;
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 	if (!is_inside_world()) {
 	if (!is_inside_world()) {
 		return;
 		return;
@@ -514,6 +555,7 @@ void Node3D::update_gizmos() {
 }
 }
 
 
 void Node3D::set_subgizmo_selection(Ref<Node3DGizmo> p_gizmo, int p_id, Transform3D p_transform) {
 void Node3D::set_subgizmo_selection(Ref<Node3DGizmo> p_gizmo, int p_id, Transform3D p_transform) {
+	ERR_THREAD_GUARD;
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 	if (!is_inside_world()) {
 	if (!is_inside_world()) {
 		return;
 		return;
@@ -526,6 +568,7 @@ void Node3D::set_subgizmo_selection(Ref<Node3DGizmo> p_gizmo, int p_id, Transfor
 }
 }
 
 
 void Node3D::clear_subgizmo_selection() {
 void Node3D::clear_subgizmo_selection() {
+	ERR_THREAD_GUARD;
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 	if (!is_inside_world()) {
 	if (!is_inside_world()) {
 		return;
 		return;
@@ -542,6 +585,7 @@ void Node3D::clear_subgizmo_selection() {
 }
 }
 
 
 void Node3D::add_gizmo(Ref<Node3DGizmo> p_gizmo) {
 void Node3D::add_gizmo(Ref<Node3DGizmo> p_gizmo) {
+	ERR_THREAD_GUARD;
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 	if (data.gizmos_disabled || p_gizmo.is_null()) {
 	if (data.gizmos_disabled || p_gizmo.is_null()) {
 		return;
 		return;
@@ -559,6 +603,7 @@ void Node3D::add_gizmo(Ref<Node3DGizmo> p_gizmo) {
 }
 }
 
 
 void Node3D::remove_gizmo(Ref<Node3DGizmo> p_gizmo) {
 void Node3D::remove_gizmo(Ref<Node3DGizmo> p_gizmo) {
+	ERR_THREAD_GUARD;
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 	int idx = data.gizmos.find(p_gizmo);
 	int idx = data.gizmos.find(p_gizmo);
 	if (idx != -1) {
 	if (idx != -1) {
@@ -569,6 +614,7 @@ void Node3D::remove_gizmo(Ref<Node3DGizmo> p_gizmo) {
 }
 }
 
 
 void Node3D::clear_gizmos() {
 void Node3D::clear_gizmos() {
+	ERR_THREAD_GUARD;
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 	for (int i = 0; i < data.gizmos.size(); i++) {
 	for (int i = 0; i < data.gizmos.size(); i++) {
 		data.gizmos.write[i]->free();
 		data.gizmos.write[i]->free();
@@ -578,6 +624,7 @@ void Node3D::clear_gizmos() {
 }
 }
 
 
 TypedArray<Node3DGizmo> Node3D::get_gizmos_bind() const {
 TypedArray<Node3DGizmo> Node3D::get_gizmos_bind() const {
+	ERR_THREAD_GUARD_V(TypedArray<Node3DGizmo>());
 	TypedArray<Node3DGizmo> ret;
 	TypedArray<Node3DGizmo> ret;
 
 
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
@@ -590,6 +637,7 @@ TypedArray<Node3DGizmo> Node3D::get_gizmos_bind() const {
 }
 }
 
 
 Vector<Ref<Node3DGizmo>> Node3D::get_gizmos() const {
 Vector<Ref<Node3DGizmo>> Node3D::get_gizmos() const {
+	ERR_THREAD_GUARD_V(Vector<Ref<Node3DGizmo>>());
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 	return data.gizmos;
 	return data.gizmos;
 #else
 #else
@@ -615,6 +663,7 @@ void Node3D::_update_gizmos() {
 }
 }
 
 
 void Node3D::set_disable_gizmos(bool p_enabled) {
 void Node3D::set_disable_gizmos(bool p_enabled) {
+	ERR_THREAD_GUARD;
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 	data.gizmos_disabled = p_enabled;
 	data.gizmos_disabled = p_enabled;
 	if (!p_enabled) {
 	if (!p_enabled) {
@@ -624,6 +673,7 @@ void Node3D::set_disable_gizmos(bool p_enabled) {
 }
 }
 
 
 void Node3D::reparent(Node *p_parent, bool p_keep_global_transform) {
 void Node3D::reparent(Node *p_parent, bool p_keep_global_transform) {
+	ERR_THREAD_GUARD;
 	Transform3D temp = get_global_transform();
 	Transform3D temp = get_global_transform();
 	Node::reparent(p_parent);
 	Node::reparent(p_parent);
 	if (p_keep_global_transform) {
 	if (p_keep_global_transform) {
@@ -632,14 +682,17 @@ void Node3D::reparent(Node *p_parent, bool p_keep_global_transform) {
 }
 }
 
 
 void Node3D::set_disable_scale(bool p_enabled) {
 void Node3D::set_disable_scale(bool p_enabled) {
+	ERR_THREAD_GUARD;
 	data.disable_scale = p_enabled;
 	data.disable_scale = p_enabled;
 }
 }
 
 
 bool Node3D::is_scale_disabled() const {
 bool Node3D::is_scale_disabled() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return data.disable_scale;
 	return data.disable_scale;
 }
 }
 
 
 void Node3D::set_as_top_level(bool p_enabled) {
 void Node3D::set_as_top_level(bool p_enabled) {
+	ERR_THREAD_GUARD;
 	if (data.top_level == p_enabled) {
 	if (data.top_level == p_enabled) {
 		return;
 		return;
 	}
 	}
@@ -658,10 +711,12 @@ void Node3D::set_as_top_level(bool p_enabled) {
 }
 }
 
 
 bool Node3D::is_set_as_top_level() const {
 bool Node3D::is_set_as_top_level() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return data.top_level;
 	return data.top_level;
 }
 }
 
 
 Ref<World3D> Node3D::get_world_3d() const {
 Ref<World3D> Node3D::get_world_3d() const {
+	ERR_READ_THREAD_GUARD_V(Ref<World3D>()); // World3D can only be set from main thread, so it's safe to obtain on threads.
 	ERR_FAIL_COND_V(!is_inside_world(), Ref<World3D>());
 	ERR_FAIL_COND_V(!is_inside_world(), Ref<World3D>());
 	ERR_FAIL_COND_V(!data.viewport, Ref<World3D>());
 	ERR_FAIL_COND_V(!data.viewport, Ref<World3D>());
 
 
@@ -688,14 +743,17 @@ void Node3D::_propagate_visibility_changed() {
 }
 }
 
 
 void Node3D::show() {
 void Node3D::show() {
+	ERR_MAIN_THREAD_GUARD;
 	set_visible(true);
 	set_visible(true);
 }
 }
 
 
 void Node3D::hide() {
 void Node3D::hide() {
+	ERR_MAIN_THREAD_GUARD;
 	set_visible(false);
 	set_visible(false);
 }
 }
 
 
 void Node3D::set_visible(bool p_visible) {
 void Node3D::set_visible(bool p_visible) {
+	ERR_MAIN_THREAD_GUARD;
 	if (data.visible == p_visible) {
 	if (data.visible == p_visible) {
 		return;
 		return;
 	}
 	}
@@ -709,10 +767,12 @@ void Node3D::set_visible(bool p_visible) {
 }
 }
 
 
 bool Node3D::is_visible() const {
 bool Node3D::is_visible() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return data.visible;
 	return data.visible;
 }
 }
 
 
 bool Node3D::is_visible_in_tree() const {
 bool Node3D::is_visible_in_tree() const {
+	ERR_READ_THREAD_GUARD_V(false); // Since visibility can only be changed from main thread, this is safe to call.
 	const Node3D *s = this;
 	const Node3D *s = this;
 
 
 	while (s) {
 	while (s) {
@@ -726,42 +786,49 @@ bool Node3D::is_visible_in_tree() const {
 }
 }
 
 
 void Node3D::rotate_object_local(const Vector3 &p_axis, real_t p_angle) {
 void Node3D::rotate_object_local(const Vector3 &p_axis, real_t p_angle) {
+	ERR_THREAD_GUARD;
 	Transform3D t = get_transform();
 	Transform3D t = get_transform();
 	t.basis.rotate_local(p_axis, p_angle);
 	t.basis.rotate_local(p_axis, p_angle);
 	set_transform(t);
 	set_transform(t);
 }
 }
 
 
 void Node3D::rotate(const Vector3 &p_axis, real_t p_angle) {
 void Node3D::rotate(const Vector3 &p_axis, real_t p_angle) {
+	ERR_THREAD_GUARD;
 	Transform3D t = get_transform();
 	Transform3D t = get_transform();
 	t.basis.rotate(p_axis, p_angle);
 	t.basis.rotate(p_axis, p_angle);
 	set_transform(t);
 	set_transform(t);
 }
 }
 
 
 void Node3D::rotate_x(real_t p_angle) {
 void Node3D::rotate_x(real_t p_angle) {
+	ERR_THREAD_GUARD;
 	Transform3D t = get_transform();
 	Transform3D t = get_transform();
 	t.basis.rotate(Vector3(1, 0, 0), p_angle);
 	t.basis.rotate(Vector3(1, 0, 0), p_angle);
 	set_transform(t);
 	set_transform(t);
 }
 }
 
 
 void Node3D::rotate_y(real_t p_angle) {
 void Node3D::rotate_y(real_t p_angle) {
+	ERR_THREAD_GUARD;
 	Transform3D t = get_transform();
 	Transform3D t = get_transform();
 	t.basis.rotate(Vector3(0, 1, 0), p_angle);
 	t.basis.rotate(Vector3(0, 1, 0), p_angle);
 	set_transform(t);
 	set_transform(t);
 }
 }
 
 
 void Node3D::rotate_z(real_t p_angle) {
 void Node3D::rotate_z(real_t p_angle) {
+	ERR_THREAD_GUARD;
 	Transform3D t = get_transform();
 	Transform3D t = get_transform();
 	t.basis.rotate(Vector3(0, 0, 1), p_angle);
 	t.basis.rotate(Vector3(0, 0, 1), p_angle);
 	set_transform(t);
 	set_transform(t);
 }
 }
 
 
 void Node3D::translate(const Vector3 &p_offset) {
 void Node3D::translate(const Vector3 &p_offset) {
+	ERR_THREAD_GUARD;
 	Transform3D t = get_transform();
 	Transform3D t = get_transform();
 	t.translate_local(p_offset);
 	t.translate_local(p_offset);
 	set_transform(t);
 	set_transform(t);
 }
 }
 
 
 void Node3D::translate_object_local(const Vector3 &p_offset) {
 void Node3D::translate_object_local(const Vector3 &p_offset) {
+	ERR_THREAD_GUARD;
 	Transform3D t = get_transform();
 	Transform3D t = get_transform();
 
 
 	Transform3D s;
 	Transform3D s;
@@ -770,52 +837,61 @@ void Node3D::translate_object_local(const Vector3 &p_offset) {
 }
 }
 
 
 void Node3D::scale(const Vector3 &p_ratio) {
 void Node3D::scale(const Vector3 &p_ratio) {
+	ERR_THREAD_GUARD;
 	Transform3D t = get_transform();
 	Transform3D t = get_transform();
 	t.basis.scale(p_ratio);
 	t.basis.scale(p_ratio);
 	set_transform(t);
 	set_transform(t);
 }
 }
 
 
 void Node3D::scale_object_local(const Vector3 &p_scale) {
 void Node3D::scale_object_local(const Vector3 &p_scale) {
+	ERR_THREAD_GUARD;
 	Transform3D t = get_transform();
 	Transform3D t = get_transform();
 	t.basis.scale_local(p_scale);
 	t.basis.scale_local(p_scale);
 	set_transform(t);
 	set_transform(t);
 }
 }
 
 
 void Node3D::global_rotate(const Vector3 &p_axis, real_t p_angle) {
 void Node3D::global_rotate(const Vector3 &p_axis, real_t p_angle) {
+	ERR_THREAD_GUARD;
 	Transform3D t = get_global_transform();
 	Transform3D t = get_global_transform();
 	t.basis.rotate(p_axis, p_angle);
 	t.basis.rotate(p_axis, p_angle);
 	set_global_transform(t);
 	set_global_transform(t);
 }
 }
 
 
 void Node3D::global_scale(const Vector3 &p_scale) {
 void Node3D::global_scale(const Vector3 &p_scale) {
+	ERR_THREAD_GUARD;
 	Transform3D t = get_global_transform();
 	Transform3D t = get_global_transform();
 	t.basis.scale(p_scale);
 	t.basis.scale(p_scale);
 	set_global_transform(t);
 	set_global_transform(t);
 }
 }
 
 
 void Node3D::global_translate(const Vector3 &p_offset) {
 void Node3D::global_translate(const Vector3 &p_offset) {
+	ERR_THREAD_GUARD;
 	Transform3D t = get_global_transform();
 	Transform3D t = get_global_transform();
 	t.origin += p_offset;
 	t.origin += p_offset;
 	set_global_transform(t);
 	set_global_transform(t);
 }
 }
 
 
 void Node3D::orthonormalize() {
 void Node3D::orthonormalize() {
+	ERR_THREAD_GUARD;
 	Transform3D t = get_transform();
 	Transform3D t = get_transform();
 	t.orthonormalize();
 	t.orthonormalize();
 	set_transform(t);
 	set_transform(t);
 }
 }
 
 
 void Node3D::set_identity() {
 void Node3D::set_identity() {
+	ERR_THREAD_GUARD;
 	set_transform(Transform3D());
 	set_transform(Transform3D());
 }
 }
 
 
 void Node3D::look_at(const Vector3 &p_target, const Vector3 &p_up) {
 void Node3D::look_at(const Vector3 &p_target, const Vector3 &p_up) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!is_inside_tree(), "Node not inside tree. Use look_at_from_position() instead.");
 	ERR_FAIL_COND_MSG(!is_inside_tree(), "Node not inside tree. Use look_at_from_position() instead.");
 	Vector3 origin = get_global_transform().origin;
 	Vector3 origin = get_global_transform().origin;
 	look_at_from_position(origin, p_target, p_up);
 	look_at_from_position(origin, p_target, p_up);
 }
 }
 
 
 void Node3D::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) {
 void Node3D::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(p_pos.is_equal_approx(p_target), "Node origin and target are in the same position, look_at() failed.");
 	ERR_FAIL_COND_MSG(p_pos.is_equal_approx(p_target), "Node origin and target are in the same position, look_at() failed.");
 	ERR_FAIL_COND_MSG(p_up.is_zero_approx(), "The up vector can't be zero, look_at() failed.");
 	ERR_FAIL_COND_MSG(p_up.is_zero_approx(), "The up vector can't be zero, look_at() failed.");
 	ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos).is_zero_approx(), "Up vector and direction between node origin and target are aligned, look_at() failed.");
 	ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos).is_zero_approx(), "Up vector and direction between node origin and target are aligned, look_at() failed.");
@@ -827,30 +903,37 @@ void Node3D::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target
 }
 }
 
 
 Vector3 Node3D::to_local(Vector3 p_global) const {
 Vector3 Node3D::to_local(Vector3 p_global) const {
+	ERR_READ_THREAD_GUARD_V(Vector3());
 	return get_global_transform().affine_inverse().xform(p_global);
 	return get_global_transform().affine_inverse().xform(p_global);
 }
 }
 
 
 Vector3 Node3D::to_global(Vector3 p_local) const {
 Vector3 Node3D::to_global(Vector3 p_local) const {
+	ERR_READ_THREAD_GUARD_V(Vector3());
 	return get_global_transform().xform(p_local);
 	return get_global_transform().xform(p_local);
 }
 }
 
 
 void Node3D::set_notify_transform(bool p_enabled) {
 void Node3D::set_notify_transform(bool p_enabled) {
+	ERR_THREAD_GUARD;
 	data.notify_transform = p_enabled;
 	data.notify_transform = p_enabled;
 }
 }
 
 
 bool Node3D::is_transform_notification_enabled() const {
 bool Node3D::is_transform_notification_enabled() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return data.notify_transform;
 	return data.notify_transform;
 }
 }
 
 
 void Node3D::set_notify_local_transform(bool p_enabled) {
 void Node3D::set_notify_local_transform(bool p_enabled) {
+	ERR_THREAD_GUARD;
 	data.notify_local_transform = p_enabled;
 	data.notify_local_transform = p_enabled;
 }
 }
 
 
 bool Node3D::is_local_transform_notification_enabled() const {
 bool Node3D::is_local_transform_notification_enabled() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return data.notify_local_transform;
 	return data.notify_local_transform;
 }
 }
 
 
 void Node3D::force_update_transform() {
 void Node3D::force_update_transform() {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND(!is_inside_tree());
 	ERR_FAIL_COND(!is_inside_tree());
 	if (!xform_change.in_list()) {
 	if (!xform_change.in_list()) {
 		return; //nothing to update
 		return; //nothing to update
@@ -894,6 +977,7 @@ void Node3D::_update_visibility_parent(bool p_update_root) {
 }
 }
 
 
 void Node3D::set_visibility_parent(const NodePath &p_path) {
 void Node3D::set_visibility_parent(const NodePath &p_path) {
+	ERR_MAIN_THREAD_GUARD;
 	visibility_parent_path = p_path;
 	visibility_parent_path = p_path;
 	if (is_inside_tree()) {
 	if (is_inside_tree()) {
 		_update_visibility_parent(true);
 		_update_visibility_parent(true);
@@ -901,6 +985,7 @@ void Node3D::set_visibility_parent(const NodePath &p_path) {
 }
 }
 
 
 NodePath Node3D::get_visibility_parent() const {
 NodePath Node3D::get_visibility_parent() const {
+	ERR_READ_THREAD_GUARD_V(NodePath());
 	return visibility_parent_path;
 	return visibility_parent_path;
 }
 }
 
 

+ 3 - 2
scene/3d/node_3d.h

@@ -88,6 +88,7 @@ private:
 	mutable SelfList<Node> xform_change;
 	mutable SelfList<Node> xform_change;
 
 
 	// This Data struct is to avoid namespace pollution in derived classes.
 	// This Data struct is to avoid namespace pollution in derived classes.
+
 	struct Data {
 	struct Data {
 		mutable Transform3D global_transform;
 		mutable Transform3D global_transform;
 		mutable Transform3D local_transform;
 		mutable Transform3D local_transform;
@@ -96,7 +97,7 @@ private:
 		mutable Vector3 scale = Vector3(1, 1, 1);
 		mutable Vector3 scale = Vector3(1, 1, 1);
 		mutable RotationEditMode rotation_edit_mode = ROTATION_EDIT_MODE_EULER;
 		mutable RotationEditMode rotation_edit_mode = ROTATION_EDIT_MODE_EULER;
 
 
-		mutable int dirty = DIRTY_NONE;
+		mutable SafeNumeric<uint32_t> dirty;
 
 
 		Viewport *viewport = nullptr;
 		Viewport *viewport = nullptr;
 
 
@@ -106,7 +107,6 @@ private:
 
 
 		RID visibility_parent;
 		RID visibility_parent;
 
 
-		int children_lock = 0;
 		Node3D *parent = nullptr;
 		Node3D *parent = nullptr;
 		List<Node3D *> children;
 		List<Node3D *> children;
 		List<Node3D *>::Element *C = nullptr;
 		List<Node3D *>::Element *C = nullptr;
@@ -137,6 +137,7 @@ private:
 
 
 	void _propagate_visibility_parent();
 	void _propagate_visibility_parent();
 	void _update_visibility_parent(bool p_update_root);
 	void _update_visibility_parent(bool p_update_root);
+	void _propagate_transform_changed_deferred();
 
 
 protected:
 protected:
 	_FORCE_INLINE_ void set_ignore_transform_notification(bool p_ignore) { data.ignore_notification = p_ignore; }
 	_FORCE_INLINE_ void set_ignore_transform_notification(bool p_ignore) { data.ignore_notification = p_ignore; }

File diff suppressed because it is too large
+ 144 - 0
scene/gui/control.cpp


+ 124 - 10
scene/main/canvas_item.cpp

@@ -56,6 +56,7 @@ Transform2D CanvasItem::_edit_get_transform() const {
 #endif
 #endif
 
 
 bool CanvasItem::is_visible_in_tree() const {
 bool CanvasItem::is_visible_in_tree() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return visible && parent_visible_in_tree;
 	return visible && parent_visible_in_tree;
 }
 }
 
 
@@ -69,6 +70,7 @@ void CanvasItem::_propagate_visibility_changed(bool p_parent_visible_in_tree) {
 }
 }
 
 
 void CanvasItem::set_visible(bool p_visible) {
 void CanvasItem::set_visible(bool p_visible) {
+	ERR_MAIN_THREAD_GUARD;
 	if (visible == p_visible) {
 	if (visible == p_visible) {
 		return;
 		return;
 	}
 	}
@@ -105,14 +107,17 @@ void CanvasItem::_handle_visibility_change(bool p_visible) {
 }
 }
 
 
 void CanvasItem::show() {
 void CanvasItem::show() {
+	ERR_MAIN_THREAD_GUARD;
 	set_visible(true);
 	set_visible(true);
 }
 }
 
 
 void CanvasItem::hide() {
 void CanvasItem::hide() {
+	ERR_MAIN_THREAD_GUARD;
 	set_visible(false);
 	set_visible(false);
 }
 }
 
 
 bool CanvasItem::is_visible() const {
 bool CanvasItem::is_visible() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return visible;
 	return visible;
 }
 }
 
 
@@ -143,10 +148,11 @@ void CanvasItem::_redraw_callback() {
 }
 }
 
 
 void CanvasItem::_invalidate_global_transform() {
 void CanvasItem::_invalidate_global_transform() {
-	global_invalid = true;
+	global_invalid.set();
 }
 }
 
 
 Transform2D CanvasItem::get_global_transform_with_canvas() const {
 Transform2D CanvasItem::get_global_transform_with_canvas() const {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
 	if (canvas_layer) {
 	if (canvas_layer) {
 		return canvas_layer->get_final_transform() * get_global_transform();
 		return canvas_layer->get_final_transform() * get_global_transform();
 	} else if (is_inside_tree()) {
 	} else if (is_inside_tree()) {
@@ -157,20 +163,26 @@ Transform2D CanvasItem::get_global_transform_with_canvas() const {
 }
 }
 
 
 Transform2D CanvasItem::get_screen_transform() const {
 Transform2D CanvasItem::get_screen_transform() const {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
 	ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
 	ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
 	return get_viewport()->get_popup_base_transform() * get_global_transform_with_canvas();
 	return get_viewport()->get_popup_base_transform() * get_global_transform_with_canvas();
 }
 }
 
 
 Transform2D CanvasItem::get_global_transform() const {
 Transform2D CanvasItem::get_global_transform() const {
-	if (global_invalid) {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
+
+	if (global_invalid.is_set()) {
+		// This code can enter multiple times from threads if dirty, this is expected.
 		const CanvasItem *pi = get_parent_item();
 		const CanvasItem *pi = get_parent_item();
+		Transform2D new_global;
 		if (pi) {
 		if (pi) {
-			global_transform = pi->get_global_transform() * get_transform();
+			new_global = pi->get_global_transform() * get_transform();
 		} else {
 		} else {
-			global_transform = get_transform();
+			new_global = get_transform();
 		}
 		}
 
 
-		global_invalid = false;
+		global_transform = new_global;
+		global_invalid.clear();
 	}
 	}
 
 
 	return global_transform;
 	return global_transform;
@@ -253,6 +265,8 @@ void CanvasItem::_exit_canvas() {
 }
 }
 
 
 void CanvasItem::_notification(int p_what) {
 void CanvasItem::_notification(int p_what) {
+	ERR_MAIN_THREAD_GUARD;
+
 	switch (p_what) {
 	switch (p_what) {
 		case NOTIFICATION_ENTER_TREE: {
 		case NOTIFICATION_ENTER_TREE: {
 			ERR_FAIL_COND(!is_inside_tree());
 			ERR_FAIL_COND(!is_inside_tree());
@@ -294,7 +308,7 @@ void CanvasItem::_notification(int p_what) {
 				}
 				}
 			}
 			}
 
 
-			global_invalid = true;
+			global_invalid.set();
 			_enter_canvas();
 			_enter_canvas();
 
 
 			RenderingServer::get_singleton()->canvas_item_set_visible(canvas_item, is_visible_in_tree()); // The visibility of the parent may change.
 			RenderingServer::get_singleton()->canvas_item_set_visible(canvas_item, is_visible_in_tree()); // The visibility of the parent may change.
@@ -327,7 +341,7 @@ void CanvasItem::_notification(int p_what) {
 				window->disconnect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed));
 				window->disconnect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed));
 				window = nullptr;
 				window = nullptr;
 			}
 			}
-			global_invalid = true;
+			global_invalid.set();
 			parent_visible_in_tree = false;
 			parent_visible_in_tree = false;
 
 
 			if (get_viewport()) {
 			if (get_viewport()) {
@@ -346,6 +360,8 @@ void CanvasItem::_notification(int p_what) {
 }
 }
 
 
 void CanvasItem::update_draw_order() {
 void CanvasItem::update_draw_order() {
+	ERR_MAIN_THREAD_GUARD;
+
 	if (!is_inside_tree()) {
 	if (!is_inside_tree()) {
 		return;
 		return;
 	}
 	}
@@ -363,6 +379,7 @@ void CanvasItem::_window_visibility_changed() {
 }
 }
 
 
 void CanvasItem::queue_redraw() {
 void CanvasItem::queue_redraw() {
+	ERR_THREAD_GUARD; // Calling from thread is safe.
 	if (!is_inside_tree()) {
 	if (!is_inside_tree()) {
 		return;
 		return;
 	}
 	}
@@ -376,6 +393,7 @@ void CanvasItem::queue_redraw() {
 }
 }
 
 
 void CanvasItem::move_to_front() {
 void CanvasItem::move_to_front() {
+	ERR_MAIN_THREAD_GUARD;
 	if (!get_parent()) {
 	if (!get_parent()) {
 		return;
 		return;
 	}
 	}
@@ -383,6 +401,7 @@ void CanvasItem::move_to_front() {
 }
 }
 
 
 void CanvasItem::set_modulate(const Color &p_modulate) {
 void CanvasItem::set_modulate(const Color &p_modulate) {
+	ERR_THREAD_GUARD;
 	if (modulate == p_modulate) {
 	if (modulate == p_modulate) {
 		return;
 		return;
 	}
 	}
@@ -392,10 +411,12 @@ void CanvasItem::set_modulate(const Color &p_modulate) {
 }
 }
 
 
 Color CanvasItem::get_modulate() const {
 Color CanvasItem::get_modulate() const {
+	ERR_READ_THREAD_GUARD_V(Color());
 	return modulate;
 	return modulate;
 }
 }
 
 
 Color CanvasItem::get_modulate_in_tree() const {
 Color CanvasItem::get_modulate_in_tree() const {
+	ERR_READ_THREAD_GUARD_V(Color());
 	Color final_modulate = modulate;
 	Color final_modulate = modulate;
 	CanvasItem *parent_item = get_parent_item();
 	CanvasItem *parent_item = get_parent_item();
 	while (parent_item) {
 	while (parent_item) {
@@ -406,6 +427,7 @@ Color CanvasItem::get_modulate_in_tree() const {
 }
 }
 
 
 void CanvasItem::set_as_top_level(bool p_top_level) {
 void CanvasItem::set_as_top_level(bool p_top_level) {
+	ERR_MAIN_THREAD_GUARD;
 	if (top_level == p_top_level) {
 	if (top_level == p_top_level) {
 		return;
 		return;
 	}
 	}
@@ -445,6 +467,7 @@ bool CanvasItem::is_set_as_top_level() const {
 }
 }
 
 
 CanvasItem *CanvasItem::get_parent_item() const {
 CanvasItem *CanvasItem::get_parent_item() const {
+	ERR_READ_THREAD_GUARD_V(nullptr);
 	if (top_level) {
 	if (top_level) {
 		return nullptr;
 		return nullptr;
 	}
 	}
@@ -453,6 +476,7 @@ CanvasItem *CanvasItem::get_parent_item() const {
 }
 }
 
 
 void CanvasItem::set_self_modulate(const Color &p_self_modulate) {
 void CanvasItem::set_self_modulate(const Color &p_self_modulate) {
+	ERR_THREAD_GUARD;
 	if (self_modulate == p_self_modulate) {
 	if (self_modulate == p_self_modulate) {
 		return;
 		return;
 	}
 	}
@@ -462,10 +486,12 @@ void CanvasItem::set_self_modulate(const Color &p_self_modulate) {
 }
 }
 
 
 Color CanvasItem::get_self_modulate() const {
 Color CanvasItem::get_self_modulate() const {
+	ERR_READ_THREAD_GUARD_V(Color());
 	return self_modulate;
 	return self_modulate;
 }
 }
 
 
 void CanvasItem::set_light_mask(int p_light_mask) {
 void CanvasItem::set_light_mask(int p_light_mask) {
+	ERR_THREAD_GUARD;
 	if (light_mask == p_light_mask) {
 	if (light_mask == p_light_mask) {
 		return;
 		return;
 	}
 	}
@@ -475,10 +501,12 @@ void CanvasItem::set_light_mask(int p_light_mask) {
 }
 }
 
 
 int CanvasItem::get_light_mask() const {
 int CanvasItem::get_light_mask() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	return light_mask;
 	return light_mask;
 }
 }
 
 
 void CanvasItem::item_rect_changed(bool p_size_changed) {
 void CanvasItem::item_rect_changed(bool p_size_changed) {
+	ERR_MAIN_THREAD_GUARD;
 	if (p_size_changed) {
 	if (p_size_changed) {
 		queue_redraw();
 		queue_redraw();
 	}
 	}
@@ -486,6 +514,7 @@ void CanvasItem::item_rect_changed(bool p_size_changed) {
 }
 }
 
 
 void CanvasItem::set_z_index(int p_z) {
 void CanvasItem::set_z_index(int p_z) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND(p_z < RS::CANVAS_ITEM_Z_MIN);
 	ERR_FAIL_COND(p_z < RS::CANVAS_ITEM_Z_MIN);
 	ERR_FAIL_COND(p_z > RS::CANVAS_ITEM_Z_MAX);
 	ERR_FAIL_COND(p_z > RS::CANVAS_ITEM_Z_MAX);
 	z_index = p_z;
 	z_index = p_z;
@@ -494,6 +523,7 @@ void CanvasItem::set_z_index(int p_z) {
 }
 }
 
 
 void CanvasItem::set_z_as_relative(bool p_enabled) {
 void CanvasItem::set_z_as_relative(bool p_enabled) {
+	ERR_THREAD_GUARD;
 	if (z_relative == p_enabled) {
 	if (z_relative == p_enabled) {
 		return;
 		return;
 	}
 	}
@@ -502,14 +532,17 @@ void CanvasItem::set_z_as_relative(bool p_enabled) {
 }
 }
 
 
 bool CanvasItem::is_z_relative() const {
 bool CanvasItem::is_z_relative() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return z_relative;
 	return z_relative;
 }
 }
 
 
 int CanvasItem::get_z_index() const {
 int CanvasItem::get_z_index() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	return z_index;
 	return z_index;
 }
 }
 
 
 int CanvasItem::get_effective_z_index() const {
 int CanvasItem::get_effective_z_index() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	int effective_z_index = z_index;
 	int effective_z_index = z_index;
 	if (is_z_relative()) {
 	if (is_z_relative()) {
 		CanvasItem *p = get_parent_item();
 		CanvasItem *p = get_parent_item();
@@ -521,15 +554,18 @@ int CanvasItem::get_effective_z_index() const {
 }
 }
 
 
 void CanvasItem::set_y_sort_enabled(bool p_enabled) {
 void CanvasItem::set_y_sort_enabled(bool p_enabled) {
+	ERR_THREAD_GUARD;
 	y_sort_enabled = p_enabled;
 	y_sort_enabled = p_enabled;
 	RS::get_singleton()->canvas_item_set_sort_children_by_y(canvas_item, y_sort_enabled);
 	RS::get_singleton()->canvas_item_set_sort_children_by_y(canvas_item, y_sort_enabled);
 }
 }
 
 
 bool CanvasItem::is_y_sort_enabled() const {
 bool CanvasItem::is_y_sort_enabled() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return y_sort_enabled;
 	return y_sort_enabled;
 }
 }
 
 
 void CanvasItem::draw_dashed_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width, real_t p_dash, bool p_aligned) {
 void CanvasItem::draw_dashed_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width, real_t p_dash, bool p_aligned) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND(p_dash <= 0.0);
 	ERR_FAIL_COND(p_dash <= 0.0);
 
 
@@ -565,12 +601,14 @@ void CanvasItem::draw_dashed_line(const Point2 &p_from, const Point2 &p_to, cons
 }
 }
 
 
 void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width, bool p_antialiased) {
 void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width, bool p_antialiased) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 
 	RenderingServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width, p_antialiased);
 	RenderingServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width, p_antialiased);
 }
 }
 
 
 void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width, bool p_antialiased) {
 void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width, bool p_antialiased) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 
 	Vector<Color> colors = { p_color };
 	Vector<Color> colors = { p_color };
@@ -578,12 +616,14 @@ void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_co
 }
 }
 
 
 void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width, bool p_antialiased) {
 void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width, bool p_antialiased) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 
 	RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width, p_antialiased);
 	RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width, p_antialiased);
 }
 }
 
 
 void CanvasItem::draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width, bool p_antialiased) {
 void CanvasItem::draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width, bool p_antialiased) {
+	ERR_THREAD_GUARD;
 	Vector<Point2> points;
 	Vector<Point2> points;
 	points.resize(p_point_count);
 	points.resize(p_point_count);
 	Point2 *points_ptr = points.ptrw();
 	Point2 *points_ptr = points.ptrw();
@@ -599,6 +639,7 @@ void CanvasItem::draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_sta
 }
 }
 
 
 void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width) {
 void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 
 	Vector<Color> colors = { p_color };
 	Vector<Color> colors = { p_color };
@@ -606,12 +647,14 @@ void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_c
 }
 }
 
 
 void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width) {
 void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 
 	RenderingServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, p_colors, p_width);
 	RenderingServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, p_colors, p_width);
 }
 }
 
 
 void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled, real_t p_width) {
 void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled, real_t p_width) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 
 	Rect2 rect = p_rect.abs();
 	Rect2 rect = p_rect.abs();
@@ -640,12 +683,14 @@ void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_fil
 }
 }
 
 
 void CanvasItem::draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color) {
 void CanvasItem::draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 
 	RenderingServer::get_singleton()->canvas_item_add_circle(canvas_item, p_pos, p_radius, p_color);
 	RenderingServer::get_singleton()->canvas_item_add_circle(canvas_item, p_pos, p_radius, p_color);
 }
 }
 
 
 void CanvasItem::draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate) {
 void CanvasItem::draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 
 	ERR_FAIL_COND(p_texture.is_null());
 	ERR_FAIL_COND(p_texture.is_null());
@@ -654,6 +699,7 @@ void CanvasItem::draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_p
 }
 }
 
 
 void CanvasItem::draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) {
 void CanvasItem::draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 
 	ERR_FAIL_COND(p_texture.is_null());
 	ERR_FAIL_COND(p_texture.is_null());
@@ -661,24 +707,28 @@ void CanvasItem::draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2
 }
 }
 
 
 void CanvasItem::draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) {
 void CanvasItem::draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND(p_texture.is_null());
 	ERR_FAIL_COND(p_texture.is_null());
 	p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_clip_uv);
 	p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_clip_uv);
 }
 }
 
 
 void CanvasItem::draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, double p_outline, double p_pixel_range, double p_scale) {
 void CanvasItem::draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, double p_outline, double p_pixel_range, double p_scale) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND(p_texture.is_null());
 	ERR_FAIL_COND(p_texture.is_null());
 	RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate, p_outline, p_pixel_range, p_scale);
 	RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate, p_outline, p_pixel_range, p_scale);
 }
 }
 
 
 void CanvasItem::draw_lcd_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate) {
 void CanvasItem::draw_lcd_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND(p_texture.is_null());
 	ERR_FAIL_COND(p_texture.is_null());
 	RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate);
 	RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate);
 }
 }
 
 
 void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect) {
 void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 
 	ERR_FAIL_COND(p_style_box.is_null());
 	ERR_FAIL_COND(p_style_box.is_null());
@@ -687,6 +737,7 @@ void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p
 }
 }
 
 
 void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) {
 void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 
 	RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
 	RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
@@ -694,6 +745,7 @@ void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Col
 }
 }
 
 
 void CanvasItem::draw_set_transform(const Point2 &p_offset, real_t p_rot, const Size2 &p_scale) {
 void CanvasItem::draw_set_transform(const Point2 &p_offset, real_t p_rot, const Size2 &p_scale) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 
 	Transform2D xform(p_rot, p_offset);
 	Transform2D xform(p_rot, p_offset);
@@ -702,23 +754,27 @@ void CanvasItem::draw_set_transform(const Point2 &p_offset, real_t p_rot, const
 }
 }
 
 
 void CanvasItem::draw_set_transform_matrix(const Transform2D &p_matrix) {
 void CanvasItem::draw_set_transform_matrix(const Transform2D &p_matrix) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 
 	RenderingServer::get_singleton()->canvas_item_add_set_transform(canvas_item, p_matrix);
 	RenderingServer::get_singleton()->canvas_item_add_set_transform(canvas_item, p_matrix);
 }
 }
 void CanvasItem::draw_animation_slice(double p_animation_length, double p_slice_begin, double p_slice_end, double p_offset) {
 void CanvasItem::draw_animation_slice(double p_animation_length, double p_slice_begin, double p_slice_end, double p_offset) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 
 	RenderingServer::get_singleton()->canvas_item_add_animation_slice(canvas_item, p_animation_length, p_slice_begin, p_slice_end, p_offset);
 	RenderingServer::get_singleton()->canvas_item_add_animation_slice(canvas_item, p_animation_length, p_slice_begin, p_slice_end, p_offset);
 }
 }
 
 
 void CanvasItem::draw_end_animation() {
 void CanvasItem::draw_end_animation() {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 
 	RenderingServer::get_singleton()->canvas_item_add_animation_slice(canvas_item, 1, 0, 2, 0);
 	RenderingServer::get_singleton()->canvas_item_add_animation_slice(canvas_item, 1, 0, 2, 0);
 }
 }
 
 
 void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) {
 void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 
 	RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
 	RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
@@ -727,6 +783,7 @@ void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color
 }
 }
 
 
 void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) {
 void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 
 	Vector<Color> colors = { p_color };
 	Vector<Color> colors = { p_color };
@@ -735,6 +792,7 @@ void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Colo
 }
 }
 
 
 void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Transform2D &p_transform, const Color &p_modulate) {
 void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Transform2D &p_transform, const Color &p_modulate) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND(p_mesh.is_null());
 	ERR_FAIL_COND(p_mesh.is_null());
 	RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
 	RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
 
 
@@ -742,12 +800,14 @@ void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_text
 }
 }
 
 
 void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture) {
 void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND(p_multimesh.is_null());
 	ERR_FAIL_COND(p_multimesh.is_null());
 	RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
 	RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
 	RenderingServer::get_singleton()->canvas_item_add_multimesh(canvas_item, p_multimesh->get_rid(), texture_rid);
 	RenderingServer::get_singleton()->canvas_item_add_multimesh(canvas_item, p_multimesh->get_rid(), texture_rid);
 }
 }
 
 
 void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
 void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND(p_font.is_null());
 	ERR_FAIL_COND(p_font.is_null());
 
 
@@ -755,6 +815,7 @@ void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const
 }
 }
 
 
 void CanvasItem::draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
 void CanvasItem::draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND(p_font.is_null());
 	ERR_FAIL_COND(p_font.is_null());
 
 
@@ -762,6 +823,7 @@ void CanvasItem::draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_
 }
 }
 
 
 void CanvasItem::draw_string_outline(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
 void CanvasItem::draw_string_outline(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND(p_font.is_null());
 	ERR_FAIL_COND(p_font.is_null());
 
 
@@ -769,6 +831,7 @@ void CanvasItem::draw_string_outline(const Ref<Font> &p_font, const Point2 &p_po
 }
 }
 
 
 void CanvasItem::draw_multiline_string_outline(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, int p_size, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
 void CanvasItem::draw_multiline_string_outline(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, int p_size, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND(p_font.is_null());
 	ERR_FAIL_COND(p_font.is_null());
 
 
@@ -776,6 +839,7 @@ void CanvasItem::draw_multiline_string_outline(const Ref<Font> &p_font, const Po
 }
 }
 
 
 void CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, int p_font_size, const Color &p_modulate) const {
 void CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, int p_font_size, const Color &p_modulate) const {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND(p_char.length() != 1);
 	ERR_FAIL_COND(p_char.length() != 1);
 	ERR_FAIL_COND(p_font.is_null());
 	ERR_FAIL_COND(p_font.is_null());
@@ -784,6 +848,7 @@ void CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const S
 }
 }
 
 
 void CanvasItem::draw_char_outline(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, int p_font_size, int p_size, const Color &p_modulate) const {
 void CanvasItem::draw_char_outline(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, int p_font_size, int p_size, const Color &p_modulate) const {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND(p_char.length() != 1);
 	ERR_FAIL_COND(p_char.length() != 1);
 	ERR_FAIL_COND(p_font.is_null());
 	ERR_FAIL_COND(p_font.is_null());
@@ -791,6 +856,12 @@ void CanvasItem::draw_char_outline(const Ref<Font> &p_font, const Point2 &p_pos,
 	p_font->draw_char_outline(canvas_item, p_pos, p_char[0], p_font_size, p_size, p_modulate);
 	p_font->draw_char_outline(canvas_item, p_pos, p_char[0], p_font_size, p_size, p_modulate);
 }
 }
 
 
+void CanvasItem::_notify_transform_deferred() {
+	if (is_inside_tree() && notify_transform && !xform_change.in_list()) {
+		get_tree()->xform_change_list.add(&xform_change);
+	}
+}
+
 void CanvasItem::_notify_transform(CanvasItem *p_node) {
 void CanvasItem::_notify_transform(CanvasItem *p_node) {
 	/* This check exists to avoid re-propagating the transform
 	/* This check exists to avoid re-propagating the transform
 	 * notification down the tree on dirty nodes. It provides
 	 * notification down the tree on dirty nodes. It provides
@@ -798,16 +869,21 @@ void CanvasItem::_notify_transform(CanvasItem *p_node) {
 	 * notification anyway).
 	 * notification anyway).
 	 */
 	 */
 
 
-	if (/*p_node->xform_change.in_list() &&*/ p_node->global_invalid) {
+	if (/*p_node->xform_change.in_list() &&*/ p_node->global_invalid.is_set()) {
 		return; //nothing to do
 		return; //nothing to do
 	}
 	}
 
 
-	p_node->global_invalid = true;
+	p_node->global_invalid.set();
 
 
 	if (p_node->notify_transform && !p_node->xform_change.in_list()) {
 	if (p_node->notify_transform && !p_node->xform_change.in_list()) {
 		if (!p_node->block_transform_notify) {
 		if (!p_node->block_transform_notify) {
 			if (p_node->is_inside_tree()) {
 			if (p_node->is_inside_tree()) {
-				get_tree()->xform_change_list.add(&p_node->xform_change);
+				if (is_accessible_from_caller_thread()) {
+					get_tree()->xform_change_list.add(&p_node->xform_change);
+				} else {
+					// Should be rare, but still needs to be handled.
+					MessageQueue::get_singleton()->push_callable(callable_mp(p_node, &CanvasItem::_notify_transform_deferred));
+				}
 			}
 			}
 		}
 		}
 	}
 	}
@@ -821,11 +897,13 @@ void CanvasItem::_notify_transform(CanvasItem *p_node) {
 }
 }
 
 
 Rect2 CanvasItem::get_viewport_rect() const {
 Rect2 CanvasItem::get_viewport_rect() const {
+	ERR_READ_THREAD_GUARD_V(Rect2());
 	ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
 	ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
 	return get_viewport()->get_visible_rect();
 	return get_viewport()->get_visible_rect();
 }
 }
 
 
 RID CanvasItem::get_canvas() const {
 RID CanvasItem::get_canvas() const {
+	ERR_READ_THREAD_GUARD_V(RID());
 	ERR_FAIL_COND_V(!is_inside_tree(), RID());
 	ERR_FAIL_COND_V(!is_inside_tree(), RID());
 
 
 	if (canvas_layer) {
 	if (canvas_layer) {
@@ -836,6 +914,7 @@ RID CanvasItem::get_canvas() const {
 }
 }
 
 
 ObjectID CanvasItem::get_canvas_layer_instance_id() const {
 ObjectID CanvasItem::get_canvas_layer_instance_id() const {
+	ERR_READ_THREAD_GUARD_V(ObjectID());
 	if (canvas_layer) {
 	if (canvas_layer) {
 		return canvas_layer->get_instance_id();
 		return canvas_layer->get_instance_id();
 	} else {
 	} else {
@@ -844,6 +923,7 @@ ObjectID CanvasItem::get_canvas_layer_instance_id() const {
 }
 }
 
 
 CanvasItem *CanvasItem::get_top_level() const {
 CanvasItem *CanvasItem::get_top_level() const {
+	ERR_READ_THREAD_GUARD_V(nullptr);
 	CanvasItem *ci = const_cast<CanvasItem *>(this);
 	CanvasItem *ci = const_cast<CanvasItem *>(this);
 	while (!ci->top_level && Object::cast_to<CanvasItem>(ci->get_parent())) {
 	while (!ci->top_level && Object::cast_to<CanvasItem>(ci->get_parent())) {
 		ci = Object::cast_to<CanvasItem>(ci->get_parent());
 		ci = Object::cast_to<CanvasItem>(ci->get_parent());
@@ -853,6 +933,7 @@ CanvasItem *CanvasItem::get_top_level() const {
 }
 }
 
 
 Ref<World2D> CanvasItem::get_world_2d() const {
 Ref<World2D> CanvasItem::get_world_2d() const {
+	ERR_READ_THREAD_GUARD_V(Ref<World2D>());
 	ERR_FAIL_COND_V(!is_inside_tree(), Ref<World2D>());
 	ERR_FAIL_COND_V(!is_inside_tree(), Ref<World2D>());
 
 
 	CanvasItem *tl = get_top_level();
 	CanvasItem *tl = get_top_level();
@@ -865,19 +946,23 @@ Ref<World2D> CanvasItem::get_world_2d() const {
 }
 }
 
 
 RID CanvasItem::get_viewport_rid() const {
 RID CanvasItem::get_viewport_rid() const {
+	ERR_READ_THREAD_GUARD_V(RID());
 	ERR_FAIL_COND_V(!is_inside_tree(), RID());
 	ERR_FAIL_COND_V(!is_inside_tree(), RID());
 	return get_viewport()->get_viewport_rid();
 	return get_viewport()->get_viewport_rid();
 }
 }
 
 
 void CanvasItem::set_block_transform_notify(bool p_enable) {
 void CanvasItem::set_block_transform_notify(bool p_enable) {
+	ERR_THREAD_GUARD;
 	block_transform_notify = p_enable;
 	block_transform_notify = p_enable;
 }
 }
 
 
 bool CanvasItem::is_block_transform_notify_enabled() const {
 bool CanvasItem::is_block_transform_notify_enabled() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return block_transform_notify;
 	return block_transform_notify;
 }
 }
 
 
 void CanvasItem::set_draw_behind_parent(bool p_enable) {
 void CanvasItem::set_draw_behind_parent(bool p_enable) {
+	ERR_THREAD_GUARD;
 	if (behind == p_enable) {
 	if (behind == p_enable) {
 		return;
 		return;
 	}
 	}
@@ -886,10 +971,12 @@ void CanvasItem::set_draw_behind_parent(bool p_enable) {
 }
 }
 
 
 bool CanvasItem::is_draw_behind_parent_enabled() const {
 bool CanvasItem::is_draw_behind_parent_enabled() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return behind;
 	return behind;
 }
 }
 
 
 void CanvasItem::set_material(const Ref<Material> &p_material) {
 void CanvasItem::set_material(const Ref<Material> &p_material) {
+	ERR_THREAD_GUARD;
 	material = p_material;
 	material = p_material;
 	RID rid;
 	RID rid;
 	if (material.is_valid()) {
 	if (material.is_valid()) {
@@ -900,19 +987,23 @@ void CanvasItem::set_material(const Ref<Material> &p_material) {
 }
 }
 
 
 void CanvasItem::set_use_parent_material(bool p_use_parent_material) {
 void CanvasItem::set_use_parent_material(bool p_use_parent_material) {
+	ERR_THREAD_GUARD;
 	use_parent_material = p_use_parent_material;
 	use_parent_material = p_use_parent_material;
 	RS::get_singleton()->canvas_item_set_use_parent_material(canvas_item, p_use_parent_material);
 	RS::get_singleton()->canvas_item_set_use_parent_material(canvas_item, p_use_parent_material);
 }
 }
 
 
 bool CanvasItem::get_use_parent_material() const {
 bool CanvasItem::get_use_parent_material() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return use_parent_material;
 	return use_parent_material;
 }
 }
 
 
 Ref<Material> CanvasItem::get_material() const {
 Ref<Material> CanvasItem::get_material() const {
+	ERR_READ_THREAD_GUARD_V(Ref<Material>());
 	return material;
 	return material;
 }
 }
 
 
 Vector2 CanvasItem::make_canvas_position_local(const Vector2 &screen_point) const {
 Vector2 CanvasItem::make_canvas_position_local(const Vector2 &screen_point) const {
+	ERR_READ_THREAD_GUARD_V(Vector2());
 	ERR_FAIL_COND_V(!is_inside_tree(), screen_point);
 	ERR_FAIL_COND_V(!is_inside_tree(), screen_point);
 
 
 	Transform2D local_matrix = (get_canvas_transform() * get_global_transform()).affine_inverse();
 	Transform2D local_matrix = (get_canvas_transform() * get_global_transform()).affine_inverse();
@@ -921,6 +1012,7 @@ Vector2 CanvasItem::make_canvas_position_local(const Vector2 &screen_point) cons
 }
 }
 
 
 Ref<InputEvent> CanvasItem::make_input_local(const Ref<InputEvent> &p_event) const {
 Ref<InputEvent> CanvasItem::make_input_local(const Ref<InputEvent> &p_event) const {
+	ERR_READ_THREAD_GUARD_V(Ref<InputEvent>());
 	ERR_FAIL_COND_V(p_event.is_null(), p_event);
 	ERR_FAIL_COND_V(p_event.is_null(), p_event);
 	ERR_FAIL_COND_V(!is_inside_tree(), p_event);
 	ERR_FAIL_COND_V(!is_inside_tree(), p_event);
 
 
@@ -928,17 +1020,20 @@ Ref<InputEvent> CanvasItem::make_input_local(const Ref<InputEvent> &p_event) con
 }
 }
 
 
 Vector2 CanvasItem::get_global_mouse_position() const {
 Vector2 CanvasItem::get_global_mouse_position() const {
+	ERR_READ_THREAD_GUARD_V(Vector2());
 	ERR_FAIL_COND_V(!get_viewport(), Vector2());
 	ERR_FAIL_COND_V(!get_viewport(), Vector2());
 	return get_canvas_transform().affine_inverse().xform(get_viewport()->get_mouse_position());
 	return get_canvas_transform().affine_inverse().xform(get_viewport()->get_mouse_position());
 }
 }
 
 
 Vector2 CanvasItem::get_local_mouse_position() const {
 Vector2 CanvasItem::get_local_mouse_position() const {
+	ERR_READ_THREAD_GUARD_V(Vector2());
 	ERR_FAIL_COND_V(!get_viewport(), Vector2());
 	ERR_FAIL_COND_V(!get_viewport(), Vector2());
 
 
 	return get_global_transform().affine_inverse().xform(get_global_mouse_position());
 	return get_global_transform().affine_inverse().xform(get_global_mouse_position());
 }
 }
 
 
 void CanvasItem::force_update_transform() {
 void CanvasItem::force_update_transform() {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND(!is_inside_tree());
 	ERR_FAIL_COND(!is_inside_tree());
 	if (!xform_change.in_list()) {
 	if (!xform_change.in_list()) {
 		return;
 		return;
@@ -1148,6 +1243,7 @@ void CanvasItem::_bind_methods() {
 }
 }
 
 
 Transform2D CanvasItem::get_canvas_transform() const {
 Transform2D CanvasItem::get_canvas_transform() const {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
 	ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
 	ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
 
 
 	if (canvas_layer) {
 	if (canvas_layer) {
@@ -1160,6 +1256,7 @@ Transform2D CanvasItem::get_canvas_transform() const {
 }
 }
 
 
 Transform2D CanvasItem::get_viewport_transform() const {
 Transform2D CanvasItem::get_viewport_transform() const {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
 	ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
 	ERR_FAIL_COND_V(!is_inside_tree(), Transform2D());
 
 
 	if (canvas_layer) {
 	if (canvas_layer) {
@@ -1170,14 +1267,17 @@ Transform2D CanvasItem::get_viewport_transform() const {
 }
 }
 
 
 void CanvasItem::set_notify_local_transform(bool p_enable) {
 void CanvasItem::set_notify_local_transform(bool p_enable) {
+	ERR_THREAD_GUARD;
 	notify_local_transform = p_enable;
 	notify_local_transform = p_enable;
 }
 }
 
 
 bool CanvasItem::is_local_transform_notification_enabled() const {
 bool CanvasItem::is_local_transform_notification_enabled() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return notify_local_transform;
 	return notify_local_transform;
 }
 }
 
 
 void CanvasItem::set_notify_transform(bool p_enable) {
 void CanvasItem::set_notify_transform(bool p_enable) {
+	ERR_THREAD_GUARD;
 	if (notify_transform == p_enable) {
 	if (notify_transform == p_enable) {
 		return;
 		return;
 	}
 	}
@@ -1191,10 +1291,12 @@ void CanvasItem::set_notify_transform(bool p_enable) {
 }
 }
 
 
 bool CanvasItem::is_transform_notification_enabled() const {
 bool CanvasItem::is_transform_notification_enabled() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return notify_transform;
 	return notify_transform;
 }
 }
 
 
 int CanvasItem::get_canvas_layer() const {
 int CanvasItem::get_canvas_layer() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	if (canvas_layer) {
 	if (canvas_layer) {
 		return canvas_layer->get_layer();
 		return canvas_layer->get_layer();
 	} else {
 	} else {
@@ -1203,15 +1305,18 @@ int CanvasItem::get_canvas_layer() const {
 }
 }
 
 
 void CanvasItem::set_visibility_layer(uint32_t p_visibility_layer) {
 void CanvasItem::set_visibility_layer(uint32_t p_visibility_layer) {
+	ERR_THREAD_GUARD;
 	visibility_layer = p_visibility_layer;
 	visibility_layer = p_visibility_layer;
 	RenderingServer::get_singleton()->canvas_item_set_visibility_layer(canvas_item, p_visibility_layer);
 	RenderingServer::get_singleton()->canvas_item_set_visibility_layer(canvas_item, p_visibility_layer);
 }
 }
 
 
 uint32_t CanvasItem::get_visibility_layer() const {
 uint32_t CanvasItem::get_visibility_layer() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	return visibility_layer;
 	return visibility_layer;
 }
 }
 
 
 void CanvasItem::set_visibility_layer_bit(uint32_t p_visibility_layer, bool p_enable) {
 void CanvasItem::set_visibility_layer_bit(uint32_t p_visibility_layer, bool p_enable) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_UNSIGNED_INDEX(p_visibility_layer, 32);
 	ERR_FAIL_UNSIGNED_INDEX(p_visibility_layer, 32);
 	if (p_enable) {
 	if (p_enable) {
 		set_visibility_layer(visibility_layer | (1 << p_visibility_layer));
 		set_visibility_layer(visibility_layer | (1 << p_visibility_layer));
@@ -1221,6 +1326,7 @@ void CanvasItem::set_visibility_layer_bit(uint32_t p_visibility_layer, bool p_en
 }
 }
 
 
 bool CanvasItem::get_visibility_layer_bit(uint32_t p_visibility_layer) const {
 bool CanvasItem::get_visibility_layer_bit(uint32_t p_visibility_layer) const {
+	ERR_READ_THREAD_GUARD_V(0);
 	ERR_FAIL_UNSIGNED_INDEX_V(p_visibility_layer, 32, false);
 	ERR_FAIL_UNSIGNED_INDEX_V(p_visibility_layer, 32, false);
 	return (visibility_layer & (1 << p_visibility_layer));
 	return (visibility_layer & (1 << p_visibility_layer));
 }
 }
@@ -1261,6 +1367,7 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
 }
 }
 
 
 void CanvasItem::set_texture_filter(TextureFilter p_texture_filter) {
 void CanvasItem::set_texture_filter(TextureFilter p_texture_filter) {
+	ERR_MAIN_THREAD_GUARD; // Goes down in the tree, so only main thread can set.
 	ERR_FAIL_INDEX(p_texture_filter, TEXTURE_FILTER_MAX);
 	ERR_FAIL_INDEX(p_texture_filter, TEXTURE_FILTER_MAX);
 	if (texture_filter == p_texture_filter) {
 	if (texture_filter == p_texture_filter) {
 		return;
 		return;
@@ -1271,6 +1378,7 @@ void CanvasItem::set_texture_filter(TextureFilter p_texture_filter) {
 }
 }
 
 
 CanvasItem::TextureFilter CanvasItem::get_texture_filter() const {
 CanvasItem::TextureFilter CanvasItem::get_texture_filter() const {
+	ERR_READ_THREAD_GUARD_V(TEXTURE_FILTER_NEAREST);
 	return texture_filter;
 	return texture_filter;
 }
 }
 
 
@@ -1309,6 +1417,7 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
 }
 }
 
 
 void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) {
 void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) {
+	ERR_MAIN_THREAD_GUARD; // Goes down in the tree, so only main thread can set.
 	ERR_FAIL_INDEX(p_texture_repeat, TEXTURE_REPEAT_MAX);
 	ERR_FAIL_INDEX(p_texture_repeat, TEXTURE_REPEAT_MAX);
 	if (texture_repeat == p_texture_repeat) {
 	if (texture_repeat == p_texture_repeat) {
 		return;
 		return;
@@ -1319,6 +1428,7 @@ void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) {
 }
 }
 
 
 void CanvasItem::set_clip_children_mode(ClipChildrenMode p_clip_mode) {
 void CanvasItem::set_clip_children_mode(ClipChildrenMode p_clip_mode) {
+	ERR_THREAD_GUARD;
 	ERR_FAIL_COND(p_clip_mode >= CLIP_CHILDREN_MAX);
 	ERR_FAIL_COND(p_clip_mode >= CLIP_CHILDREN_MAX);
 
 
 	if (clip_children_mode == p_clip_mode) {
 	if (clip_children_mode == p_clip_mode) {
@@ -1334,19 +1444,23 @@ void CanvasItem::set_clip_children_mode(ClipChildrenMode p_clip_mode) {
 	RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CanvasGroupMode(clip_children_mode));
 	RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CanvasGroupMode(clip_children_mode));
 }
 }
 CanvasItem::ClipChildrenMode CanvasItem::get_clip_children_mode() const {
 CanvasItem::ClipChildrenMode CanvasItem::get_clip_children_mode() const {
+	ERR_READ_THREAD_GUARD_V(CLIP_CHILDREN_DISABLED);
 	return clip_children_mode;
 	return clip_children_mode;
 }
 }
 
 
 CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const {
 CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const {
+	ERR_READ_THREAD_GUARD_V(TEXTURE_REPEAT_DISABLED);
 	return texture_repeat;
 	return texture_repeat;
 }
 }
 
 
 CanvasItem::TextureFilter CanvasItem::get_texture_filter_in_tree() {
 CanvasItem::TextureFilter CanvasItem::get_texture_filter_in_tree() {
+	ERR_READ_THREAD_GUARD_V(TEXTURE_FILTER_NEAREST);
 	_refresh_texture_filter_cache();
 	_refresh_texture_filter_cache();
 	return (TextureFilter)texture_filter_cache;
 	return (TextureFilter)texture_filter_cache;
 }
 }
 
 
 CanvasItem::TextureRepeat CanvasItem::get_texture_repeat_in_tree() {
 CanvasItem::TextureRepeat CanvasItem::get_texture_repeat_in_tree() {
+	ERR_READ_THREAD_GUARD_V(TEXTURE_REPEAT_DISABLED);
 	_refresh_texture_repeat_cache();
 	_refresh_texture_repeat_cache();
 	return (TextureRepeat)texture_repeat_cache;
 	return (TextureRepeat)texture_repeat_cache;
 }
 }

+ 3 - 1
scene/main/canvas_item.h

@@ -118,7 +118,7 @@ private:
 	Ref<Material> material;
 	Ref<Material> material;
 
 
 	mutable Transform2D global_transform;
 	mutable Transform2D global_transform;
-	mutable bool global_invalid = true;
+	mutable SafeFlag global_invalid;
 
 
 	void _top_level_raise_self();
 	void _top_level_raise_self();
 
 
@@ -145,6 +145,8 @@ private:
 	void _refresh_texture_filter_cache();
 	void _refresh_texture_filter_cache();
 	void _update_texture_filter_changed(bool p_propagate);
 	void _update_texture_filter_changed(bool p_propagate);
 
 
+	void _notify_transform_deferred();
+
 protected:
 protected:
 	_FORCE_INLINE_ void _notify_transform() {
 	_FORCE_INLINE_ void _notify_transform() {
 		if (!is_inside_tree()) {
 		if (!is_inside_tree()) {

+ 90 - 0
scene/main/node.cpp

@@ -3513,3 +3513,93 @@ Node::~Node() {
 }
 }
 
 
 ////////////////////////////////
 ////////////////////////////////
+// Multithreaded locked version of Object functions.
+
+#ifdef DEBUG_ENABLED
+
+void Node::set_script(const Variant &p_script) {
+	ERR_THREAD_GUARD;
+	Object::set_script(p_script);
+}
+
+Variant Node::get_script() const {
+	ERR_THREAD_GUARD_V(Variant());
+	return Object::get_script();
+}
+
+bool Node::has_meta(const StringName &p_name) const {
+	ERR_THREAD_GUARD_V(false);
+	return Object::has_meta(p_name);
+}
+
+void Node::set_meta(const StringName &p_name, const Variant &p_value) {
+	ERR_THREAD_GUARD;
+	Object::set_meta(p_name, p_value);
+}
+
+void Node::remove_meta(const StringName &p_name) {
+	ERR_THREAD_GUARD;
+	Object::remove_meta(p_name);
+}
+
+Variant Node::get_meta(const StringName &p_name, const Variant &p_default) const {
+	ERR_THREAD_GUARD_V(Variant());
+	return Object::get_meta(p_name, p_default);
+}
+
+void Node::get_meta_list(List<StringName> *p_list) const {
+	ERR_THREAD_GUARD;
+	Object::get_meta_list(p_list);
+}
+
+Error Node::emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount) {
+	ERR_THREAD_GUARD_V(ERR_INVALID_PARAMETER);
+	return Object::emit_signalp(p_name, p_args, p_argcount);
+}
+
+bool Node::has_signal(const StringName &p_name) const {
+	ERR_THREAD_GUARD_V(false);
+	return Object::has_signal(p_name);
+}
+
+void Node::get_signal_list(List<MethodInfo> *p_signals) const {
+	ERR_THREAD_GUARD;
+	Object::get_signal_list(p_signals);
+}
+
+void Node::get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const {
+	ERR_THREAD_GUARD;
+	Object::get_signal_connection_list(p_signal, p_connections);
+}
+
+void Node::get_all_signal_connections(List<Connection> *p_connections) const {
+	ERR_THREAD_GUARD;
+	Object::get_all_signal_connections(p_connections);
+}
+
+int Node::get_persistent_signal_connection_count() const {
+	ERR_THREAD_GUARD_V(0);
+	return Object::get_persistent_signal_connection_count();
+}
+
+void Node::get_signals_connected_to_this(List<Connection> *p_connections) const {
+	ERR_THREAD_GUARD;
+	Object::get_signals_connected_to_this(p_connections);
+}
+
+Error Node::connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags) {
+	ERR_THREAD_GUARD_V(ERR_INVALID_PARAMETER);
+	return Object::connect(p_signal, p_callable, p_flags);
+}
+
+void Node::disconnect(const StringName &p_signal, const Callable &p_callable) {
+	ERR_THREAD_GUARD;
+	Object::disconnect(p_signal, p_callable);
+}
+
+bool Node::is_connected(const StringName &p_signal, const Callable &p_callable) const {
+	ERR_THREAD_GUARD_V(false);
+	return Object::is_connected(p_signal, p_callable);
+}
+
+#endif

+ 36 - 0
scene/main/node.h

@@ -529,6 +529,14 @@ public:
 		}
 		}
 	}
 	}
 
 
+	_FORCE_INLINE_ bool is_readable_from_caller_thread() const {
+		if (current_process_thread_group == nullptr) {
+			return Thread::is_main_thread();
+		} else {
+			return true;
+		}
+	}
+
 	void set_process_thread_messages(BitField<ProcessThreadMessages> p_flags);
 	void set_process_thread_messages(BitField<ProcessThreadMessages> p_flags);
 	BitField<ProcessThreadMessages> get_process_thread_messages() const;
 	BitField<ProcessThreadMessages> get_process_thread_messages() const;
 
 
@@ -647,6 +655,30 @@ public:
 	void set_thread_safe(const StringName &p_property, const Variant &p_value);
 	void set_thread_safe(const StringName &p_property, const Variant &p_value);
 	void notify_thread_safe(int p_notification);
 	void notify_thread_safe(int p_notification);
 
 
+	// These inherited functions need proper multithread locking when overridden in Node.
+#ifdef DEBUG_ENABLED
+
+	virtual void set_script(const Variant &p_script) override;
+	virtual Variant get_script() const override;
+
+	virtual bool has_meta(const StringName &p_name) const override;
+	virtual void set_meta(const StringName &p_name, const Variant &p_value) override;
+	virtual void remove_meta(const StringName &p_name) override;
+	virtual Variant get_meta(const StringName &p_name, const Variant &p_default = Variant()) const override;
+	virtual void get_meta_list(List<StringName> *p_list) const override;
+
+	virtual Error emit_signalp(const StringName &p_name, const Variant **p_args, int p_argcount) override;
+	virtual bool has_signal(const StringName &p_name) const override;
+	virtual void get_signal_list(List<MethodInfo> *p_signals) const override;
+	virtual void get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const override;
+	virtual void get_all_signal_connections(List<Connection> *p_connections) const override;
+	virtual int get_persistent_signal_connection_count() const override;
+	virtual void get_signals_connected_to_this(List<Connection> *p_connections) const override;
+
+	virtual Error connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags = 0) override;
+	virtual void disconnect(const StringName &p_signal, const Callable &p_callable) override;
+	virtual bool is_connected(const StringName &p_signal, const Callable &p_callable) const override;
+#endif
 	Node();
 	Node();
 	~Node();
 	~Node();
 };
 };
@@ -678,11 +710,15 @@ Error Node::rpc_id(int p_peer_id, const StringName &p_method, VarArgs... p_args)
 #define ERR_THREAD_GUARD_V(m_ret) ERR_FAIL_COND_V_MSG(!is_accessible_from_caller_thread(), (m_ret), "Caller thread can't call this function in this node. Use call_deferred() or call_thread_group() instead.")
 #define ERR_THREAD_GUARD_V(m_ret) ERR_FAIL_COND_V_MSG(!is_accessible_from_caller_thread(), (m_ret), "Caller thread can't call this function in this node. Use call_deferred() or call_thread_group() instead.")
 #define ERR_MAIN_THREAD_GUARD ERR_FAIL_COND_MSG(is_inside_tree() && !Thread::is_main_thread(), "This function in this node can only be accessed from the main thread. Use call_deferred() instead.");
 #define ERR_MAIN_THREAD_GUARD ERR_FAIL_COND_MSG(is_inside_tree() && !Thread::is_main_thread(), "This function in this node can only be accessed from the main thread. Use call_deferred() instead.");
 #define ERR_MAIN_THREAD_GUARD_V(m_ret) ERR_FAIL_COND_V_MSG(is_inside_tree() && !Thread::is_main_thread(), (m_ret), "This function in this node can only be accessed from the main thread. Use call_deferred() instead.")
 #define ERR_MAIN_THREAD_GUARD_V(m_ret) ERR_FAIL_COND_V_MSG(is_inside_tree() && !Thread::is_main_thread(), (m_ret), "This function in this node can only be accessed from the main thread. Use call_deferred() instead.")
+#define ERR_READ_THREAD_GUARD ERR_FAIL_COND_MSG(!is_readable_from_caller_thread(), "This function in this node can only be accessed from either the main thread or a thread group. Use call_deferred() instead.")
+#define ERR_READ_THREAD_GUARD_V(m_ret) ERR_FAIL_COND_V_MSG(!is_readable_from_caller_thread(), (m_ret), "This function in this node can only be accessed from either the main thread or a thread group. Use call_deferred() instead.")
 #else
 #else
 #define ERR_THREAD_GUARD
 #define ERR_THREAD_GUARD
 #define ERR_THREAD_GUARD_V(m_ret)
 #define ERR_THREAD_GUARD_V(m_ret)
 #define ERR_MAIN_THREAD_GUARD
 #define ERR_MAIN_THREAD_GUARD
 #define ERR_MAIN_THREAD_GUARD_V(m_ret)
 #define ERR_MAIN_THREAD_GUARD_V(m_ret)
+#define ERR_READ_THREAD_GUARD
+#define ERR_READ_THREAD_GUARD_V(m_ret)
 #endif
 #endif
 
 
 // Add these macro to your class's 'get_configuration_warnings' function to have warnings show up in the scene tree inspector.
 // Add these macro to your class's 'get_configuration_warnings' function to have warnings show up in the scene tree inspector.

+ 148 - 0
scene/main/viewport.cpp

@@ -468,6 +468,8 @@ void Viewport::_update_viewport_path() {
 }
 }
 
 
 void Viewport::_notification(int p_what) {
 void Viewport::_notification(int p_what) {
+	ERR_MAIN_THREAD_GUARD;
+
 	switch (p_what) {
 	switch (p_what) {
 		case NOTIFICATION_ENTER_TREE: {
 		case NOTIFICATION_ENTER_TREE: {
 			_update_viewport_path();
 			_update_viewport_path();
@@ -922,10 +924,12 @@ void Viewport::_process_picking() {
 }
 }
 
 
 RID Viewport::get_viewport_rid() const {
 RID Viewport::get_viewport_rid() const {
+	ERR_READ_THREAD_GUARD_V(RID());
 	return viewport;
 	return viewport;
 }
 }
 
 
 void Viewport::update_canvas_items() {
 void Viewport::update_canvas_items() {
+	ERR_MAIN_THREAD_GUARD;
 	if (!is_inside_tree()) {
 	if (!is_inside_tree()) {
 		return;
 		return;
 	}
 	}
@@ -1013,6 +1017,7 @@ bool Viewport::_is_size_allocated() const {
 }
 }
 
 
 Rect2 Viewport::get_visible_rect() const {
 Rect2 Viewport::get_visible_rect() const {
+	ERR_READ_THREAD_GUARD_V(Rect2());
 	Rect2 r;
 	Rect2 r;
 
 
 	if (size == Size2()) {
 	if (size == Size2()) {
@@ -1029,6 +1034,7 @@ Rect2 Viewport::get_visible_rect() const {
 }
 }
 
 
 void Viewport::canvas_parent_mark_dirty(Node *p_node) {
 void Viewport::canvas_parent_mark_dirty(Node *p_node) {
+	ERR_MAIN_THREAD_GUARD;
 	bool request_update = gui.canvas_parents_with_dirty_order.is_empty();
 	bool request_update = gui.canvas_parents_with_dirty_order.is_empty();
 	gui.canvas_parents_with_dirty_order.insert(p_node->get_instance_id());
 	gui.canvas_parents_with_dirty_order.insert(p_node->get_instance_id());
 	if (request_update) {
 	if (request_update) {
@@ -1043,6 +1049,7 @@ void Viewport::_update_audio_listener_2d() {
 }
 }
 
 
 void Viewport::set_as_audio_listener_2d(bool p_enable) {
 void Viewport::set_as_audio_listener_2d(bool p_enable) {
+	ERR_MAIN_THREAD_GUARD;
 	if (p_enable == is_audio_listener_2d_enabled) {
 	if (p_enable == is_audio_listener_2d_enabled) {
 		return;
 		return;
 	}
 	}
@@ -1052,14 +1059,17 @@ void Viewport::set_as_audio_listener_2d(bool p_enable) {
 }
 }
 
 
 bool Viewport::is_audio_listener_2d() const {
 bool Viewport::is_audio_listener_2d() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return is_audio_listener_2d_enabled;
 	return is_audio_listener_2d_enabled;
 }
 }
 
 
 AudioListener2D *Viewport::get_audio_listener_2d() const {
 AudioListener2D *Viewport::get_audio_listener_2d() const {
+	ERR_READ_THREAD_GUARD_V(nullptr);
 	return audio_listener_2d;
 	return audio_listener_2d;
 }
 }
 
 
 void Viewport::enable_canvas_transform_override(bool p_enable) {
 void Viewport::enable_canvas_transform_override(bool p_enable) {
+	ERR_MAIN_THREAD_GUARD;
 	if (override_canvas_transform == p_enable) {
 	if (override_canvas_transform == p_enable) {
 		return;
 		return;
 	}
 	}
@@ -1073,10 +1083,12 @@ void Viewport::enable_canvas_transform_override(bool p_enable) {
 }
 }
 
 
 bool Viewport::is_canvas_transform_override_enbled() const {
 bool Viewport::is_canvas_transform_override_enbled() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return override_canvas_transform;
 	return override_canvas_transform;
 }
 }
 
 
 void Viewport::set_canvas_transform_override(const Transform2D &p_transform) {
 void Viewport::set_canvas_transform_override(const Transform2D &p_transform) {
+	ERR_MAIN_THREAD_GUARD;
 	if (canvas_transform_override == p_transform) {
 	if (canvas_transform_override == p_transform) {
 		return;
 		return;
 	}
 	}
@@ -1088,10 +1100,12 @@ void Viewport::set_canvas_transform_override(const Transform2D &p_transform) {
 }
 }
 
 
 Transform2D Viewport::get_canvas_transform_override() const {
 Transform2D Viewport::get_canvas_transform_override() const {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
 	return canvas_transform_override;
 	return canvas_transform_override;
 }
 }
 
 
 void Viewport::set_canvas_transform(const Transform2D &p_transform) {
 void Viewport::set_canvas_transform(const Transform2D &p_transform) {
+	ERR_MAIN_THREAD_GUARD;
 	canvas_transform = p_transform;
 	canvas_transform = p_transform;
 
 
 	if (!override_canvas_transform) {
 	if (!override_canvas_transform) {
@@ -1100,6 +1114,7 @@ void Viewport::set_canvas_transform(const Transform2D &p_transform) {
 }
 }
 
 
 Transform2D Viewport::get_canvas_transform() const {
 Transform2D Viewport::get_canvas_transform() const {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
 	return canvas_transform;
 	return canvas_transform;
 }
 }
 
 
@@ -1110,12 +1125,14 @@ void Viewport::_update_global_transform() {
 }
 }
 
 
 void Viewport::set_global_canvas_transform(const Transform2D &p_transform) {
 void Viewport::set_global_canvas_transform(const Transform2D &p_transform) {
+	ERR_MAIN_THREAD_GUARD;
 	global_canvas_transform = p_transform;
 	global_canvas_transform = p_transform;
 
 
 	_update_global_transform();
 	_update_global_transform();
 }
 }
 
 
 Transform2D Viewport::get_global_canvas_transform() const {
 Transform2D Viewport::get_global_canvas_transform() const {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
 	return global_canvas_transform;
 	return global_canvas_transform;
 }
 }
 
 
@@ -1147,15 +1164,18 @@ void Viewport::_canvas_layer_remove(CanvasLayer *p_canvas_layer) {
 }
 }
 
 
 void Viewport::set_transparent_background(bool p_enable) {
 void Viewport::set_transparent_background(bool p_enable) {
+	ERR_MAIN_THREAD_GUARD;
 	transparent_bg = p_enable;
 	transparent_bg = p_enable;
 	RS::get_singleton()->viewport_set_transparent_background(viewport, p_enable);
 	RS::get_singleton()->viewport_set_transparent_background(viewport, p_enable);
 }
 }
 
 
 bool Viewport::has_transparent_background() const {
 bool Viewport::has_transparent_background() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return transparent_bg;
 	return transparent_bg;
 }
 }
 
 
 void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
 void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
+	ERR_MAIN_THREAD_GUARD;
 	if (world_2d == p_world_2d) {
 	if (world_2d == p_world_2d) {
 		return;
 		return;
 	}
 	}
@@ -1184,6 +1204,7 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
 }
 }
 
 
 Ref<World2D> Viewport::find_world_2d() const {
 Ref<World2D> Viewport::find_world_2d() const {
+	ERR_READ_THREAD_GUARD_V(Ref<World2D>());
 	if (world_2d.is_valid()) {
 	if (world_2d.is_valid()) {
 		return world_2d;
 		return world_2d;
 	} else if (parent) {
 	} else if (parent) {
@@ -1205,18 +1226,22 @@ void Viewport::_propagate_viewport_notification(Node *p_node, int p_what) {
 }
 }
 
 
 Ref<World2D> Viewport::get_world_2d() const {
 Ref<World2D> Viewport::get_world_2d() const {
+	ERR_READ_THREAD_GUARD_V(Ref<World2D>());
 	return world_2d;
 	return world_2d;
 }
 }
 
 
 Camera2D *Viewport::get_camera_2d() const {
 Camera2D *Viewport::get_camera_2d() const {
+	ERR_READ_THREAD_GUARD_V(nullptr);
 	return camera_2d;
 	return camera_2d;
 }
 }
 
 
 Transform2D Viewport::get_final_transform() const {
 Transform2D Viewport::get_final_transform() const {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
 	return stretch_transform * global_canvas_transform;
 	return stretch_transform * global_canvas_transform;
 }
 }
 
 
 void Viewport::assign_next_enabled_camera_2d(const StringName &p_camera_group) {
 void Viewport::assign_next_enabled_camera_2d(const StringName &p_camera_group) {
+	ERR_MAIN_THREAD_GUARD;
 	List<Node *> camera_list;
 	List<Node *> camera_list;
 	get_tree()->get_nodes_in_group(p_camera_group, &camera_list);
 	get_tree()->get_nodes_in_group(p_camera_group, &camera_list);
 
 
@@ -1260,19 +1285,23 @@ void Viewport::_update_canvas_items(Node *p_node) {
 }
 }
 
 
 Ref<ViewportTexture> Viewport::get_texture() const {
 Ref<ViewportTexture> Viewport::get_texture() const {
+	ERR_READ_THREAD_GUARD_V(Ref<ViewportTexture>());
 	return default_texture;
 	return default_texture;
 }
 }
 
 
 void Viewport::set_positional_shadow_atlas_size(int p_size) {
 void Viewport::set_positional_shadow_atlas_size(int p_size) {
+	ERR_MAIN_THREAD_GUARD;
 	positional_shadow_atlas_size = p_size;
 	positional_shadow_atlas_size = p_size;
 	RS::get_singleton()->viewport_set_positional_shadow_atlas_size(viewport, p_size, positional_shadow_atlas_16_bits);
 	RS::get_singleton()->viewport_set_positional_shadow_atlas_size(viewport, p_size, positional_shadow_atlas_16_bits);
 }
 }
 
 
 int Viewport::get_positional_shadow_atlas_size() const {
 int Viewport::get_positional_shadow_atlas_size() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	return positional_shadow_atlas_size;
 	return positional_shadow_atlas_size;
 }
 }
 
 
 void Viewport::set_positional_shadow_atlas_16_bits(bool p_16_bits) {
 void Viewport::set_positional_shadow_atlas_16_bits(bool p_16_bits) {
+	ERR_MAIN_THREAD_GUARD;
 	if (positional_shadow_atlas_16_bits == p_16_bits) {
 	if (positional_shadow_atlas_16_bits == p_16_bits) {
 		return;
 		return;
 	}
 	}
@@ -1282,9 +1311,11 @@ void Viewport::set_positional_shadow_atlas_16_bits(bool p_16_bits) {
 }
 }
 
 
 bool Viewport::get_positional_shadow_atlas_16_bits() const {
 bool Viewport::get_positional_shadow_atlas_16_bits() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return positional_shadow_atlas_16_bits;
 	return positional_shadow_atlas_16_bits;
 }
 }
 void Viewport::set_positional_shadow_atlas_quadrant_subdiv(int p_quadrant, PositionalShadowAtlasQuadrantSubdiv p_subdiv) {
 void Viewport::set_positional_shadow_atlas_quadrant_subdiv(int p_quadrant, PositionalShadowAtlasQuadrantSubdiv p_subdiv) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_INDEX(p_quadrant, 4);
 	ERR_FAIL_INDEX(p_quadrant, 4);
 	ERR_FAIL_INDEX(p_subdiv, SHADOW_ATLAS_QUADRANT_SUBDIV_MAX);
 	ERR_FAIL_INDEX(p_subdiv, SHADOW_ATLAS_QUADRANT_SUBDIV_MAX);
 
 
@@ -1299,6 +1330,7 @@ void Viewport::set_positional_shadow_atlas_quadrant_subdiv(int p_quadrant, Posit
 }
 }
 
 
 Viewport::PositionalShadowAtlasQuadrantSubdiv Viewport::get_positional_shadow_atlas_quadrant_subdiv(int p_quadrant) const {
 Viewport::PositionalShadowAtlasQuadrantSubdiv Viewport::get_positional_shadow_atlas_quadrant_subdiv(int p_quadrant) const {
+	ERR_READ_THREAD_GUARD_V(SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED);
 	ERR_FAIL_INDEX_V(p_quadrant, 4, SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED);
 	ERR_FAIL_INDEX_V(p_quadrant, 4, SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED);
 	return positional_shadow_atlas_quadrant_subdiv[p_quadrant];
 	return positional_shadow_atlas_quadrant_subdiv[p_quadrant];
 }
 }
@@ -1313,6 +1345,7 @@ Ref<InputEvent> Viewport::_make_input_local(const Ref<InputEvent> &ev) {
 }
 }
 
 
 Vector2 Viewport::get_mouse_position() const {
 Vector2 Viewport::get_mouse_position() const {
+	ERR_READ_THREAD_GUARD_V(Vector2());
 	if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_MOUSE)) {
 	if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_MOUSE)) {
 		return get_screen_transform_internal(true).affine_inverse().xform(DisplayServer::get_singleton()->mouse_get_position());
 		return get_screen_transform_internal(true).affine_inverse().xform(DisplayServer::get_singleton()->mouse_get_position());
 	} else {
 	} else {
@@ -1322,6 +1355,7 @@ Vector2 Viewport::get_mouse_position() const {
 }
 }
 
 
 void Viewport::warp_mouse(const Vector2 &p_position) {
 void Viewport::warp_mouse(const Vector2 &p_position) {
+	ERR_MAIN_THREAD_GUARD;
 	Transform2D xform = get_screen_transform_internal();
 	Transform2D xform = get_screen_transform_internal();
 	Vector2 gpos = xform.xform(p_position);
 	Vector2 gpos = xform.xform(p_position);
 	Input::get_singleton()->warp_mouse(gpos);
 	Input::get_singleton()->warp_mouse(gpos);
@@ -1565,6 +1599,7 @@ void Viewport::_gui_call_notification(Control *p_control, int p_what) {
 }
 }
 
 
 Control *Viewport::gui_find_control(const Point2 &p_global) {
 Control *Viewport::gui_find_control(const Point2 &p_global) {
+	ERR_MAIN_THREAD_GUARD_V(nullptr);
 	// Handle subwindows.
 	// Handle subwindows.
 	_gui_sort_roots();
 	_gui_sort_roots();
 
 
@@ -2274,6 +2309,7 @@ List<Control *>::Element *Viewport::_gui_add_root_control(Control *p_control) {
 }
 }
 
 
 void Viewport::gui_set_root_order_dirty() {
 void Viewport::gui_set_root_order_dirty() {
+	ERR_MAIN_THREAD_GUARD;
 	gui.roots_order_dirty = true;
 	gui.roots_order_dirty = true;
 }
 }
 
 
@@ -2374,6 +2410,7 @@ void Viewport::_gui_remove_control(Control *p_control) {
 }
 }
 
 
 Window *Viewport::get_base_window() const {
 Window *Viewport::get_base_window() const {
+	ERR_READ_THREAD_GUARD_V(nullptr);
 	ERR_FAIL_COND_V(!is_inside_tree(), nullptr);
 	ERR_FAIL_COND_V(!is_inside_tree(), nullptr);
 
 
 	Viewport *v = const_cast<Viewport *>(this);
 	Viewport *v = const_cast<Viewport *>(this);
@@ -2576,6 +2613,7 @@ void Viewport::_post_gui_grab_click_focus() {
 ///////////////////////////////
 ///////////////////////////////
 
 
 void Viewport::push_text_input(const String &p_text) {
 void Viewport::push_text_input(const String &p_text) {
+	ERR_MAIN_THREAD_GUARD;
 	if (gui.subwindow_focused) {
 	if (gui.subwindow_focused) {
 		gui.subwindow_focused->push_text_input(p_text);
 		gui.subwindow_focused->push_text_input(p_text);
 		return;
 		return;
@@ -2903,6 +2941,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
 }
 }
 
 
 void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
 void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_COND(!is_inside_tree());
 	ERR_FAIL_COND(!is_inside_tree());
 
 
 	if (disable_input) {
 	if (disable_input) {
@@ -2955,6 +2994,7 @@ void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
 }
 }
 
 
 void Viewport::push_unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
 void Viewport::push_unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_COND(p_event.is_null());
 	ERR_FAIL_COND(p_event.is_null());
 	ERR_FAIL_COND(!is_inside_tree());
 	ERR_FAIL_COND(!is_inside_tree());
 	local_input_handled = false;
 	local_input_handled = false;
@@ -3004,6 +3044,7 @@ void Viewport::push_unhandled_input(const Ref<InputEvent> &p_event, bool p_local
 }
 }
 
 
 void Viewport::set_physics_object_picking(bool p_enable) {
 void Viewport::set_physics_object_picking(bool p_enable) {
+	ERR_MAIN_THREAD_GUARD;
 	physics_object_picking = p_enable;
 	physics_object_picking = p_enable;
 	if (physics_object_picking) {
 	if (physics_object_picking) {
 		add_to_group("_picking_viewports");
 		add_to_group("_picking_viewports");
@@ -3016,27 +3057,33 @@ void Viewport::set_physics_object_picking(bool p_enable) {
 }
 }
 
 
 bool Viewport::get_physics_object_picking() {
 bool Viewport::get_physics_object_picking() {
+	ERR_READ_THREAD_GUARD_V(false);
 	return physics_object_picking;
 	return physics_object_picking;
 }
 }
 
 
 void Viewport::set_physics_object_picking_sort(bool p_enable) {
 void Viewport::set_physics_object_picking_sort(bool p_enable) {
+	ERR_MAIN_THREAD_GUARD;
 	physics_object_picking_sort = p_enable;
 	physics_object_picking_sort = p_enable;
 }
 }
 
 
 bool Viewport::get_physics_object_picking_sort() {
 bool Viewport::get_physics_object_picking_sort() {
+	ERR_READ_THREAD_GUARD_V(false);
 	return physics_object_picking_sort;
 	return physics_object_picking_sort;
 }
 }
 
 
 Vector2 Viewport::get_camera_coords(const Vector2 &p_viewport_coords) const {
 Vector2 Viewport::get_camera_coords(const Vector2 &p_viewport_coords) const {
+	ERR_READ_THREAD_GUARD_V(Vector2());
 	Transform2D xf = stretch_transform * global_canvas_transform;
 	Transform2D xf = stretch_transform * global_canvas_transform;
 	return xf.xform(p_viewport_coords);
 	return xf.xform(p_viewport_coords);
 }
 }
 
 
 Vector2 Viewport::get_camera_rect_size() const {
 Vector2 Viewport::get_camera_rect_size() const {
+	ERR_READ_THREAD_GUARD_V(Vector2());
 	return size;
 	return size;
 }
 }
 
 
 void Viewport::set_disable_input(bool p_disable) {
 void Viewport::set_disable_input(bool p_disable) {
+	ERR_MAIN_THREAD_GUARD;
 	if (p_disable == disable_input) {
 	if (p_disable == disable_input) {
 		return;
 		return;
 	}
 	}
@@ -3049,14 +3096,17 @@ void Viewport::set_disable_input(bool p_disable) {
 }
 }
 
 
 bool Viewport::is_input_disabled() const {
 bool Viewport::is_input_disabled() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return disable_input;
 	return disable_input;
 }
 }
 
 
 Variant Viewport::gui_get_drag_data() const {
 Variant Viewport::gui_get_drag_data() const {
+	ERR_READ_THREAD_GUARD_V(Variant());
 	return gui.drag_data;
 	return gui.drag_data;
 }
 }
 
 
 PackedStringArray Viewport::get_configuration_warnings() const {
 PackedStringArray Viewport::get_configuration_warnings() const {
+	ERR_MAIN_THREAD_GUARD_V(PackedStringArray());
 	PackedStringArray warnings = Node::get_configuration_warnings();
 	PackedStringArray warnings = Node::get_configuration_warnings();
 
 
 	if (size.x <= 1 || size.y <= 1) {
 	if (size.x <= 1 || size.y <= 1) {
@@ -3066,14 +3116,17 @@ PackedStringArray Viewport::get_configuration_warnings() const {
 }
 }
 
 
 void Viewport::gui_reset_canvas_sort_index() {
 void Viewport::gui_reset_canvas_sort_index() {
+	ERR_MAIN_THREAD_GUARD;
 	gui.canvas_sort_index = 0;
 	gui.canvas_sort_index = 0;
 }
 }
 
 
 int Viewport::gui_get_canvas_sort_index() {
 int Viewport::gui_get_canvas_sort_index() {
+	ERR_MAIN_THREAD_GUARD_V(0);
 	return gui.canvas_sort_index++;
 	return gui.canvas_sort_index++;
 }
 }
 
 
 void Viewport::gui_release_focus() {
 void Viewport::gui_release_focus() {
+	ERR_MAIN_THREAD_GUARD;
 	if (gui.key_focus) {
 	if (gui.key_focus) {
 		Control *f = gui.key_focus;
 		Control *f = gui.key_focus;
 		gui.key_focus = nullptr;
 		gui.key_focus = nullptr;
@@ -3083,10 +3136,12 @@ void Viewport::gui_release_focus() {
 }
 }
 
 
 Control *Viewport::gui_get_focus_owner() {
 Control *Viewport::gui_get_focus_owner() {
+	ERR_READ_THREAD_GUARD_V(nullptr);
 	return gui.key_focus;
 	return gui.key_focus;
 }
 }
 
 
 void Viewport::set_msaa_2d(MSAA p_msaa) {
 void Viewport::set_msaa_2d(MSAA p_msaa) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_INDEX(p_msaa, MSAA_MAX);
 	ERR_FAIL_INDEX(p_msaa, MSAA_MAX);
 	if (msaa_2d == p_msaa) {
 	if (msaa_2d == p_msaa) {
 		return;
 		return;
@@ -3096,10 +3151,12 @@ void Viewport::set_msaa_2d(MSAA p_msaa) {
 }
 }
 
 
 Viewport::MSAA Viewport::get_msaa_2d() const {
 Viewport::MSAA Viewport::get_msaa_2d() const {
+	ERR_READ_THREAD_GUARD_V(MSAA_DISABLED);
 	return msaa_2d;
 	return msaa_2d;
 }
 }
 
 
 void Viewport::set_msaa_3d(MSAA p_msaa) {
 void Viewport::set_msaa_3d(MSAA p_msaa) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_INDEX(p_msaa, MSAA_MAX);
 	ERR_FAIL_INDEX(p_msaa, MSAA_MAX);
 	if (msaa_3d == p_msaa) {
 	if (msaa_3d == p_msaa) {
 		return;
 		return;
@@ -3109,10 +3166,12 @@ void Viewport::set_msaa_3d(MSAA p_msaa) {
 }
 }
 
 
 Viewport::MSAA Viewport::get_msaa_3d() const {
 Viewport::MSAA Viewport::get_msaa_3d() const {
+	ERR_READ_THREAD_GUARD_V(MSAA_DISABLED);
 	return msaa_3d;
 	return msaa_3d;
 }
 }
 
 
 void Viewport::set_screen_space_aa(ScreenSpaceAA p_screen_space_aa) {
 void Viewport::set_screen_space_aa(ScreenSpaceAA p_screen_space_aa) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_INDEX(p_screen_space_aa, SCREEN_SPACE_AA_MAX);
 	ERR_FAIL_INDEX(p_screen_space_aa, SCREEN_SPACE_AA_MAX);
 	if (screen_space_aa == p_screen_space_aa) {
 	if (screen_space_aa == p_screen_space_aa) {
 		return;
 		return;
@@ -3122,10 +3181,12 @@ void Viewport::set_screen_space_aa(ScreenSpaceAA p_screen_space_aa) {
 }
 }
 
 
 Viewport::ScreenSpaceAA Viewport::get_screen_space_aa() const {
 Viewport::ScreenSpaceAA Viewport::get_screen_space_aa() const {
+	ERR_READ_THREAD_GUARD_V(SCREEN_SPACE_AA_DISABLED);
 	return screen_space_aa;
 	return screen_space_aa;
 }
 }
 
 
 void Viewport::set_use_taa(bool p_use_taa) {
 void Viewport::set_use_taa(bool p_use_taa) {
+	ERR_MAIN_THREAD_GUARD;
 	if (use_taa == p_use_taa) {
 	if (use_taa == p_use_taa) {
 		return;
 		return;
 	}
 	}
@@ -3134,10 +3195,12 @@ void Viewport::set_use_taa(bool p_use_taa) {
 }
 }
 
 
 bool Viewport::is_using_taa() const {
 bool Viewport::is_using_taa() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return use_taa;
 	return use_taa;
 }
 }
 
 
 void Viewport::set_use_debanding(bool p_use_debanding) {
 void Viewport::set_use_debanding(bool p_use_debanding) {
+	ERR_MAIN_THREAD_GUARD;
 	if (use_debanding == p_use_debanding) {
 	if (use_debanding == p_use_debanding) {
 		return;
 		return;
 	}
 	}
@@ -3146,19 +3209,23 @@ void Viewport::set_use_debanding(bool p_use_debanding) {
 }
 }
 
 
 bool Viewport::is_using_debanding() const {
 bool Viewport::is_using_debanding() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return use_debanding;
 	return use_debanding;
 }
 }
 
 
 void Viewport::set_mesh_lod_threshold(float p_pixels) {
 void Viewport::set_mesh_lod_threshold(float p_pixels) {
+	ERR_MAIN_THREAD_GUARD;
 	mesh_lod_threshold = p_pixels;
 	mesh_lod_threshold = p_pixels;
 	RS::get_singleton()->viewport_set_mesh_lod_threshold(viewport, mesh_lod_threshold);
 	RS::get_singleton()->viewport_set_mesh_lod_threshold(viewport, mesh_lod_threshold);
 }
 }
 
 
 float Viewport::get_mesh_lod_threshold() const {
 float Viewport::get_mesh_lod_threshold() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	return mesh_lod_threshold;
 	return mesh_lod_threshold;
 }
 }
 
 
 void Viewport::set_use_occlusion_culling(bool p_use_occlusion_culling) {
 void Viewport::set_use_occlusion_culling(bool p_use_occlusion_culling) {
+	ERR_MAIN_THREAD_GUARD;
 	if (use_occlusion_culling == p_use_occlusion_culling) {
 	if (use_occlusion_culling == p_use_occlusion_culling) {
 		return;
 		return;
 	}
 	}
@@ -3170,57 +3237,70 @@ void Viewport::set_use_occlusion_culling(bool p_use_occlusion_culling) {
 }
 }
 
 
 bool Viewport::is_using_occlusion_culling() const {
 bool Viewport::is_using_occlusion_culling() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return use_occlusion_culling;
 	return use_occlusion_culling;
 }
 }
 
 
 void Viewport::set_debug_draw(DebugDraw p_debug_draw) {
 void Viewport::set_debug_draw(DebugDraw p_debug_draw) {
+	ERR_MAIN_THREAD_GUARD;
 	debug_draw = p_debug_draw;
 	debug_draw = p_debug_draw;
 	RS::get_singleton()->viewport_set_debug_draw(viewport, RS::ViewportDebugDraw(p_debug_draw));
 	RS::get_singleton()->viewport_set_debug_draw(viewport, RS::ViewportDebugDraw(p_debug_draw));
 }
 }
 
 
 Viewport::DebugDraw Viewport::get_debug_draw() const {
 Viewport::DebugDraw Viewport::get_debug_draw() const {
+	ERR_READ_THREAD_GUARD_V(DEBUG_DRAW_DISABLED);
 	return debug_draw;
 	return debug_draw;
 }
 }
 
 
 int Viewport::get_render_info(RenderInfoType p_type, RenderInfo p_info) {
 int Viewport::get_render_info(RenderInfoType p_type, RenderInfo p_info) {
+	ERR_READ_THREAD_GUARD_V(0);
 	return RS::get_singleton()->viewport_get_render_info(viewport, RS::ViewportRenderInfoType(p_type), RS::ViewportRenderInfo(p_info));
 	return RS::get_singleton()->viewport_get_render_info(viewport, RS::ViewportRenderInfoType(p_type), RS::ViewportRenderInfo(p_info));
 }
 }
 
 
 void Viewport::set_snap_controls_to_pixels(bool p_enable) {
 void Viewport::set_snap_controls_to_pixels(bool p_enable) {
+	ERR_MAIN_THREAD_GUARD;
 	snap_controls_to_pixels = p_enable;
 	snap_controls_to_pixels = p_enable;
 }
 }
 
 
 bool Viewport::is_snap_controls_to_pixels_enabled() const {
 bool Viewport::is_snap_controls_to_pixels_enabled() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return snap_controls_to_pixels;
 	return snap_controls_to_pixels;
 }
 }
 
 
 void Viewport::set_snap_2d_transforms_to_pixel(bool p_enable) {
 void Viewport::set_snap_2d_transforms_to_pixel(bool p_enable) {
+	ERR_MAIN_THREAD_GUARD;
 	snap_2d_transforms_to_pixel = p_enable;
 	snap_2d_transforms_to_pixel = p_enable;
 	RS::get_singleton()->viewport_set_snap_2d_transforms_to_pixel(viewport, snap_2d_transforms_to_pixel);
 	RS::get_singleton()->viewport_set_snap_2d_transforms_to_pixel(viewport, snap_2d_transforms_to_pixel);
 }
 }
 
 
 bool Viewport::is_snap_2d_transforms_to_pixel_enabled() const {
 bool Viewport::is_snap_2d_transforms_to_pixel_enabled() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return snap_2d_transforms_to_pixel;
 	return snap_2d_transforms_to_pixel;
 }
 }
 
 
 void Viewport::set_snap_2d_vertices_to_pixel(bool p_enable) {
 void Viewport::set_snap_2d_vertices_to_pixel(bool p_enable) {
+	ERR_MAIN_THREAD_GUARD;
 	snap_2d_vertices_to_pixel = p_enable;
 	snap_2d_vertices_to_pixel = p_enable;
 	RS::get_singleton()->viewport_set_snap_2d_vertices_to_pixel(viewport, snap_2d_vertices_to_pixel);
 	RS::get_singleton()->viewport_set_snap_2d_vertices_to_pixel(viewport, snap_2d_vertices_to_pixel);
 }
 }
 
 
 bool Viewport::is_snap_2d_vertices_to_pixel_enabled() const {
 bool Viewport::is_snap_2d_vertices_to_pixel_enabled() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return snap_2d_vertices_to_pixel;
 	return snap_2d_vertices_to_pixel;
 }
 }
 
 
 bool Viewport::gui_is_dragging() const {
 bool Viewport::gui_is_dragging() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return gui.dragging;
 	return gui.dragging;
 }
 }
 
 
 bool Viewport::gui_is_drag_successful() const {
 bool Viewport::gui_is_drag_successful() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return gui.drag_successful;
 	return gui.drag_successful;
 }
 }
 
 
 void Viewport::set_input_as_handled() {
 void Viewport::set_input_as_handled() {
+	ERR_MAIN_THREAD_GUARD;
 	if (!handle_input_locally) {
 	if (!handle_input_locally) {
 		ERR_FAIL_COND(!is_inside_tree());
 		ERR_FAIL_COND(!is_inside_tree());
 		Viewport *vp = this;
 		Viewport *vp = this;
@@ -3243,6 +3323,7 @@ void Viewport::set_input_as_handled() {
 }
 }
 
 
 bool Viewport::is_input_handled() const {
 bool Viewport::is_input_handled() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	if (!handle_input_locally) {
 	if (!handle_input_locally) {
 		ERR_FAIL_COND_V(!is_inside_tree(), false);
 		ERR_FAIL_COND_V(!is_inside_tree(), false);
 		const Viewport *vp = this;
 		const Viewport *vp = this;
@@ -3263,14 +3344,17 @@ bool Viewport::is_input_handled() const {
 }
 }
 
 
 void Viewport::set_handle_input_locally(bool p_enable) {
 void Viewport::set_handle_input_locally(bool p_enable) {
+	ERR_MAIN_THREAD_GUARD;
 	handle_input_locally = p_enable;
 	handle_input_locally = p_enable;
 }
 }
 
 
 bool Viewport::is_handling_input_locally() const {
 bool Viewport::is_handling_input_locally() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return handle_input_locally;
 	return handle_input_locally;
 }
 }
 
 
 void Viewport::set_default_canvas_item_texture_filter(DefaultCanvasItemTextureFilter p_filter) {
 void Viewport::set_default_canvas_item_texture_filter(DefaultCanvasItemTextureFilter p_filter) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_INDEX(p_filter, DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_MAX);
 	ERR_FAIL_INDEX(p_filter, DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_MAX);
 
 
 	if (default_canvas_item_texture_filter == p_filter) {
 	if (default_canvas_item_texture_filter == p_filter) {
@@ -3296,10 +3380,12 @@ void Viewport::set_default_canvas_item_texture_filter(DefaultCanvasItemTextureFi
 }
 }
 
 
 Viewport::DefaultCanvasItemTextureFilter Viewport::get_default_canvas_item_texture_filter() const {
 Viewport::DefaultCanvasItemTextureFilter Viewport::get_default_canvas_item_texture_filter() const {
+	ERR_READ_THREAD_GUARD_V(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
 	return default_canvas_item_texture_filter;
 	return default_canvas_item_texture_filter;
 }
 }
 
 
 void Viewport::set_default_canvas_item_texture_repeat(DefaultCanvasItemTextureRepeat p_repeat) {
 void Viewport::set_default_canvas_item_texture_repeat(DefaultCanvasItemTextureRepeat p_repeat) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_INDEX(p_repeat, DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX);
 	ERR_FAIL_INDEX(p_repeat, DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX);
 
 
 	if (default_canvas_item_texture_repeat == p_repeat) {
 	if (default_canvas_item_texture_repeat == p_repeat) {
@@ -3324,10 +3410,12 @@ void Viewport::set_default_canvas_item_texture_repeat(DefaultCanvasItemTextureRe
 }
 }
 
 
 Viewport::DefaultCanvasItemTextureRepeat Viewport::get_default_canvas_item_texture_repeat() const {
 Viewport::DefaultCanvasItemTextureRepeat Viewport::get_default_canvas_item_texture_repeat() const {
+	ERR_READ_THREAD_GUARD_V(DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
 	return default_canvas_item_texture_repeat;
 	return default_canvas_item_texture_repeat;
 }
 }
 
 
 void Viewport::set_vrs_mode(Viewport::VRSMode p_vrs_mode) {
 void Viewport::set_vrs_mode(Viewport::VRSMode p_vrs_mode) {
+	ERR_MAIN_THREAD_GUARD;
 	// Note, set this even if not supported on this hardware, it will only be used if it is but we want to save the value as set by the user.
 	// Note, set this even if not supported on this hardware, it will only be used if it is but we want to save the value as set by the user.
 	vrs_mode = p_vrs_mode;
 	vrs_mode = p_vrs_mode;
 
 
@@ -3347,10 +3435,12 @@ void Viewport::set_vrs_mode(Viewport::VRSMode p_vrs_mode) {
 }
 }
 
 
 Viewport::VRSMode Viewport::get_vrs_mode() const {
 Viewport::VRSMode Viewport::get_vrs_mode() const {
+	ERR_READ_THREAD_GUARD_V(VRS_DISABLED);
 	return vrs_mode;
 	return vrs_mode;
 }
 }
 
 
 void Viewport::set_vrs_texture(Ref<Texture2D> p_texture) {
 void Viewport::set_vrs_texture(Ref<Texture2D> p_texture) {
+	ERR_MAIN_THREAD_GUARD;
 	vrs_texture = p_texture;
 	vrs_texture = p_texture;
 
 
 	// TODO need to add something here in case the RID changes
 	// TODO need to add something here in case the RID changes
@@ -3359,14 +3449,17 @@ void Viewport::set_vrs_texture(Ref<Texture2D> p_texture) {
 }
 }
 
 
 Ref<Texture2D> Viewport::get_vrs_texture() const {
 Ref<Texture2D> Viewport::get_vrs_texture() const {
+	ERR_READ_THREAD_GUARD_V(Ref<Texture2D>());
 	return vrs_texture;
 	return vrs_texture;
 }
 }
 
 
 DisplayServer::WindowID Viewport::get_window_id() const {
 DisplayServer::WindowID Viewport::get_window_id() const {
+	ERR_READ_THREAD_GUARD_V(DisplayServer::INVALID_WINDOW_ID);
 	return DisplayServer::MAIN_WINDOW_ID;
 	return DisplayServer::MAIN_WINDOW_ID;
 }
 }
 
 
 Viewport *Viewport::get_parent_viewport() const {
 Viewport *Viewport::get_parent_viewport() const {
+	ERR_READ_THREAD_GUARD_V(nullptr);
 	ERR_FAIL_COND_V(!is_inside_tree(), nullptr);
 	ERR_FAIL_COND_V(!is_inside_tree(), nullptr);
 	if (!get_parent()) {
 	if (!get_parent()) {
 		return nullptr; //root viewport
 		return nullptr; //root viewport
@@ -3376,14 +3469,17 @@ Viewport *Viewport::get_parent_viewport() const {
 }
 }
 
 
 void Viewport::set_embedding_subwindows(bool p_embed) {
 void Viewport::set_embedding_subwindows(bool p_embed) {
+	ERR_THREAD_GUARD;
 	gui.embed_subwindows_hint = p_embed;
 	gui.embed_subwindows_hint = p_embed;
 }
 }
 
 
 bool Viewport::is_embedding_subwindows() const {
 bool Viewport::is_embedding_subwindows() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return gui.embed_subwindows_hint;
 	return gui.embed_subwindows_hint;
 }
 }
 
 
 void Viewport::pass_mouse_focus_to(Viewport *p_viewport, Control *p_control) {
 void Viewport::pass_mouse_focus_to(Viewport *p_viewport, Control *p_control) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_NULL(p_viewport);
 	ERR_FAIL_NULL(p_viewport);
 	ERR_FAIL_NULL(p_control);
 	ERR_FAIL_NULL(p_control);
 
 
@@ -3400,43 +3496,52 @@ void Viewport::pass_mouse_focus_to(Viewport *p_viewport, Control *p_control) {
 }
 }
 
 
 void Viewport::set_sdf_oversize(SDFOversize p_sdf_oversize) {
 void Viewport::set_sdf_oversize(SDFOversize p_sdf_oversize) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_INDEX(p_sdf_oversize, SDF_OVERSIZE_MAX);
 	ERR_FAIL_INDEX(p_sdf_oversize, SDF_OVERSIZE_MAX);
 	sdf_oversize = p_sdf_oversize;
 	sdf_oversize = p_sdf_oversize;
 	RS::get_singleton()->viewport_set_sdf_oversize_and_scale(viewport, RS::ViewportSDFOversize(sdf_oversize), RS::ViewportSDFScale(sdf_scale));
 	RS::get_singleton()->viewport_set_sdf_oversize_and_scale(viewport, RS::ViewportSDFOversize(sdf_oversize), RS::ViewportSDFScale(sdf_scale));
 }
 }
 
 
 Viewport::SDFOversize Viewport::get_sdf_oversize() const {
 Viewport::SDFOversize Viewport::get_sdf_oversize() const {
+	ERR_READ_THREAD_GUARD_V(SDF_OVERSIZE_100_PERCENT);
 	return sdf_oversize;
 	return sdf_oversize;
 }
 }
 
 
 void Viewport::set_sdf_scale(SDFScale p_sdf_scale) {
 void Viewport::set_sdf_scale(SDFScale p_sdf_scale) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_INDEX(p_sdf_scale, SDF_SCALE_MAX);
 	ERR_FAIL_INDEX(p_sdf_scale, SDF_SCALE_MAX);
 	sdf_scale = p_sdf_scale;
 	sdf_scale = p_sdf_scale;
 	RS::get_singleton()->viewport_set_sdf_oversize_and_scale(viewport, RS::ViewportSDFOversize(sdf_oversize), RS::ViewportSDFScale(sdf_scale));
 	RS::get_singleton()->viewport_set_sdf_oversize_and_scale(viewport, RS::ViewportSDFOversize(sdf_oversize), RS::ViewportSDFScale(sdf_scale));
 }
 }
 
 
 Viewport::SDFScale Viewport::get_sdf_scale() const {
 Viewport::SDFScale Viewport::get_sdf_scale() const {
+	ERR_READ_THREAD_GUARD_V(SDF_SCALE_100_PERCENT);
 	return sdf_scale;
 	return sdf_scale;
 }
 }
 
 
 Transform2D Viewport::get_screen_transform() const {
 Transform2D Viewport::get_screen_transform() const {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
 	return get_screen_transform_internal();
 	return get_screen_transform_internal();
 }
 }
 
 
 Transform2D Viewport::get_screen_transform_internal(bool p_absolute_position) const {
 Transform2D Viewport::get_screen_transform_internal(bool p_absolute_position) const {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
 	return get_final_transform();
 	return get_final_transform();
 }
 }
 
 
 void Viewport::set_canvas_cull_mask(uint32_t p_canvas_cull_mask) {
 void Viewport::set_canvas_cull_mask(uint32_t p_canvas_cull_mask) {
+	ERR_MAIN_THREAD_GUARD;
 	canvas_cull_mask = p_canvas_cull_mask;
 	canvas_cull_mask = p_canvas_cull_mask;
 	RenderingServer::get_singleton()->viewport_set_canvas_cull_mask(viewport, canvas_cull_mask);
 	RenderingServer::get_singleton()->viewport_set_canvas_cull_mask(viewport, canvas_cull_mask);
 }
 }
 
 
 uint32_t Viewport::get_canvas_cull_mask() const {
 uint32_t Viewport::get_canvas_cull_mask() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	return canvas_cull_mask;
 	return canvas_cull_mask;
 }
 }
 
 
 void Viewport::set_canvas_cull_mask_bit(uint32_t p_layer, bool p_enable) {
 void Viewport::set_canvas_cull_mask_bit(uint32_t p_layer, bool p_enable) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_UNSIGNED_INDEX(p_layer, 32);
 	ERR_FAIL_UNSIGNED_INDEX(p_layer, 32);
 	if (p_enable) {
 	if (p_enable) {
 		set_canvas_cull_mask(canvas_cull_mask | (1 << p_layer));
 		set_canvas_cull_mask(canvas_cull_mask | (1 << p_layer));
@@ -3446,16 +3551,19 @@ void Viewport::set_canvas_cull_mask_bit(uint32_t p_layer, bool p_enable) {
 }
 }
 
 
 bool Viewport::get_canvas_cull_mask_bit(uint32_t p_layer) const {
 bool Viewport::get_canvas_cull_mask_bit(uint32_t p_layer) const {
+	ERR_READ_THREAD_GUARD_V(false);
 	ERR_FAIL_UNSIGNED_INDEX_V(p_layer, 32, false);
 	ERR_FAIL_UNSIGNED_INDEX_V(p_layer, 32, false);
 	return (canvas_cull_mask & (1 << p_layer));
 	return (canvas_cull_mask & (1 << p_layer));
 }
 }
 
 
 #ifndef _3D_DISABLED
 #ifndef _3D_DISABLED
 AudioListener3D *Viewport::get_audio_listener_3d() const {
 AudioListener3D *Viewport::get_audio_listener_3d() const {
+	ERR_READ_THREAD_GUARD_V(nullptr);
 	return audio_listener_3d;
 	return audio_listener_3d;
 }
 }
 
 
 void Viewport::set_as_audio_listener_3d(bool p_enable) {
 void Viewport::set_as_audio_listener_3d(bool p_enable) {
+	ERR_MAIN_THREAD_GUARD;
 	if (p_enable == is_audio_listener_3d_enabled) {
 	if (p_enable == is_audio_listener_3d_enabled) {
 		return;
 		return;
 	}
 	}
@@ -3465,6 +3573,7 @@ void Viewport::set_as_audio_listener_3d(bool p_enable) {
 }
 }
 
 
 bool Viewport::is_audio_listener_3d() const {
 bool Viewport::is_audio_listener_3d() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return is_audio_listener_3d_enabled;
 	return is_audio_listener_3d_enabled;
 }
 }
 
 
@@ -3543,6 +3652,7 @@ void Viewport::_collision_object_3d_input_event(CollisionObject3D *p_object, Cam
 }
 }
 
 
 Camera3D *Viewport::get_camera_3d() const {
 Camera3D *Viewport::get_camera_3d() const {
+	ERR_READ_THREAD_GUARD_V(nullptr);
 	return camera_3d;
 	return camera_3d;
 }
 }
 
 
@@ -3606,6 +3716,7 @@ void Viewport::_camera_3d_make_next_current(Camera3D *p_exclude) {
 }
 }
 
 
 void Viewport::enable_camera_3d_override(bool p_enable) {
 void Viewport::enable_camera_3d_override(bool p_enable) {
+	ERR_MAIN_THREAD_GUARD;
 	if (p_enable == camera_3d_override) {
 	if (p_enable == camera_3d_override) {
 		return;
 		return;
 	}
 	}
@@ -3627,6 +3738,7 @@ void Viewport::enable_camera_3d_override(bool p_enable) {
 }
 }
 
 
 void Viewport::set_camera_3d_override_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far) {
 void Viewport::set_camera_3d_override_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far) {
+	ERR_MAIN_THREAD_GUARD;
 	if (camera_3d_override) {
 	if (camera_3d_override) {
 		if (camera_3d_override.fov == p_fovy_degrees && camera_3d_override.z_near == p_z_near &&
 		if (camera_3d_override.fov == p_fovy_degrees && camera_3d_override.z_near == p_z_near &&
 				camera_3d_override.z_far == p_z_far && camera_3d_override.projection == Camera3DOverrideData::PROJECTION_PERSPECTIVE) {
 				camera_3d_override.z_far == p_z_far && camera_3d_override.projection == Camera3DOverrideData::PROJECTION_PERSPECTIVE) {
@@ -3643,6 +3755,7 @@ void Viewport::set_camera_3d_override_perspective(real_t p_fovy_degrees, real_t
 }
 }
 
 
 void Viewport::set_camera_3d_override_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far) {
 void Viewport::set_camera_3d_override_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far) {
+	ERR_MAIN_THREAD_GUARD;
 	if (camera_3d_override) {
 	if (camera_3d_override) {
 		if (camera_3d_override.size == p_size && camera_3d_override.z_near == p_z_near &&
 		if (camera_3d_override.size == p_size && camera_3d_override.z_near == p_z_near &&
 				camera_3d_override.z_far == p_z_far && camera_3d_override.projection == Camera3DOverrideData::PROJECTION_ORTHOGONAL) {
 				camera_3d_override.z_far == p_z_far && camera_3d_override.projection == Camera3DOverrideData::PROJECTION_ORTHOGONAL) {
@@ -3659,19 +3772,23 @@ void Viewport::set_camera_3d_override_orthogonal(real_t p_size, real_t p_z_near,
 }
 }
 
 
 void Viewport::set_disable_3d(bool p_disable) {
 void Viewport::set_disable_3d(bool p_disable) {
+	ERR_MAIN_THREAD_GUARD;
 	disable_3d = p_disable;
 	disable_3d = p_disable;
 	RenderingServer::get_singleton()->viewport_set_disable_3d(viewport, disable_3d);
 	RenderingServer::get_singleton()->viewport_set_disable_3d(viewport, disable_3d);
 }
 }
 
 
 bool Viewport::is_3d_disabled() const {
 bool Viewport::is_3d_disabled() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return disable_3d;
 	return disable_3d;
 }
 }
 
 
 bool Viewport::is_camera_3d_override_enabled() const {
 bool Viewport::is_camera_3d_override_enabled() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return camera_3d_override;
 	return camera_3d_override;
 }
 }
 
 
 void Viewport::set_camera_3d_override_transform(const Transform3D &p_transform) {
 void Viewport::set_camera_3d_override_transform(const Transform3D &p_transform) {
+	ERR_MAIN_THREAD_GUARD;
 	if (camera_3d_override) {
 	if (camera_3d_override) {
 		camera_3d_override.transform = p_transform;
 		camera_3d_override.transform = p_transform;
 		RenderingServer::get_singleton()->camera_set_transform(camera_3d_override.rid, p_transform);
 		RenderingServer::get_singleton()->camera_set_transform(camera_3d_override.rid, p_transform);
@@ -3679,6 +3796,7 @@ void Viewport::set_camera_3d_override_transform(const Transform3D &p_transform)
 }
 }
 
 
 Transform3D Viewport::get_camera_3d_override_transform() const {
 Transform3D Viewport::get_camera_3d_override_transform() const {
+	ERR_READ_THREAD_GUARD_V(Transform3D());
 	if (camera_3d_override) {
 	if (camera_3d_override) {
 		return camera_3d_override.transform;
 		return camera_3d_override.transform;
 	}
 	}
@@ -3687,10 +3805,12 @@ Transform3D Viewport::get_camera_3d_override_transform() const {
 }
 }
 
 
 Ref<World3D> Viewport::get_world_3d() const {
 Ref<World3D> Viewport::get_world_3d() const {
+	ERR_READ_THREAD_GUARD_V(Ref<World3D>());
 	return world_3d;
 	return world_3d;
 }
 }
 
 
 Ref<World3D> Viewport::find_world_3d() const {
 Ref<World3D> Viewport::find_world_3d() const {
+	ERR_READ_THREAD_GUARD_V(Ref<World3D>());
 	if (own_world_3d.is_valid()) {
 	if (own_world_3d.is_valid()) {
 		return own_world_3d;
 		return own_world_3d;
 	} else if (world_3d.is_valid()) {
 	} else if (world_3d.is_valid()) {
@@ -3703,6 +3823,7 @@ Ref<World3D> Viewport::find_world_3d() const {
 }
 }
 
 
 void Viewport::set_world_3d(const Ref<World3D> &p_world_3d) {
 void Viewport::set_world_3d(const Ref<World3D> &p_world_3d) {
+	ERR_MAIN_THREAD_GUARD;
 	if (world_3d == p_world_3d) {
 	if (world_3d == p_world_3d) {
 		return;
 		return;
 	}
 	}
@@ -3759,6 +3880,7 @@ void Viewport::_own_world_3d_changed() {
 }
 }
 
 
 void Viewport::set_use_own_world_3d(bool p_use_own_world_3d) {
 void Viewport::set_use_own_world_3d(bool p_use_own_world_3d) {
+	ERR_MAIN_THREAD_GUARD;
 	if (p_use_own_world_3d == own_world_3d.is_valid()) {
 	if (p_use_own_world_3d == own_world_3d.is_valid()) {
 		return;
 		return;
 	}
 	}
@@ -3793,6 +3915,7 @@ void Viewport::set_use_own_world_3d(bool p_use_own_world_3d) {
 }
 }
 
 
 bool Viewport::is_using_own_world_3d() const {
 bool Viewport::is_using_own_world_3d() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return own_world_3d.is_valid();
 	return own_world_3d.is_valid();
 }
 }
 
 
@@ -3843,6 +3966,7 @@ void Viewport::_propagate_exit_world_3d(Node *p_node) {
 }
 }
 
 
 void Viewport::set_use_xr(bool p_use_xr) {
 void Viewport::set_use_xr(bool p_use_xr) {
+	ERR_MAIN_THREAD_GUARD;
 	if (use_xr != p_use_xr) {
 	if (use_xr != p_use_xr) {
 		use_xr = p_use_xr;
 		use_xr = p_use_xr;
 
 
@@ -3860,10 +3984,12 @@ void Viewport::set_use_xr(bool p_use_xr) {
 }
 }
 
 
 bool Viewport::is_using_xr() {
 bool Viewport::is_using_xr() {
+	ERR_READ_THREAD_GUARD_V(false);
 	return use_xr;
 	return use_xr;
 }
 }
 
 
 void Viewport::set_scaling_3d_mode(Scaling3DMode p_scaling_3d_mode) {
 void Viewport::set_scaling_3d_mode(Scaling3DMode p_scaling_3d_mode) {
+	ERR_MAIN_THREAD_GUARD;
 	if (scaling_3d_mode == p_scaling_3d_mode) {
 	if (scaling_3d_mode == p_scaling_3d_mode) {
 		return;
 		return;
 	}
 	}
@@ -3873,10 +3999,12 @@ void Viewport::set_scaling_3d_mode(Scaling3DMode p_scaling_3d_mode) {
 }
 }
 
 
 Viewport::Scaling3DMode Viewport::get_scaling_3d_mode() const {
 Viewport::Scaling3DMode Viewport::get_scaling_3d_mode() const {
+	ERR_READ_THREAD_GUARD_V(SCALING_3D_MODE_BILINEAR);
 	return scaling_3d_mode;
 	return scaling_3d_mode;
 }
 }
 
 
 void Viewport::set_scaling_3d_scale(float p_scaling_3d_scale) {
 void Viewport::set_scaling_3d_scale(float p_scaling_3d_scale) {
+	ERR_MAIN_THREAD_GUARD;
 	// Clamp to reasonable values that are actually useful.
 	// Clamp to reasonable values that are actually useful.
 	// Values above 2.0 don't serve a practical purpose since the viewport
 	// Values above 2.0 don't serve a practical purpose since the viewport
 	// isn't displayed with mipmaps.
 	// isn't displayed with mipmaps.
@@ -3886,10 +4014,12 @@ void Viewport::set_scaling_3d_scale(float p_scaling_3d_scale) {
 }
 }
 
 
 float Viewport::get_scaling_3d_scale() const {
 float Viewport::get_scaling_3d_scale() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	return scaling_3d_scale;
 	return scaling_3d_scale;
 }
 }
 
 
 void Viewport::set_fsr_sharpness(float p_fsr_sharpness) {
 void Viewport::set_fsr_sharpness(float p_fsr_sharpness) {
+	ERR_MAIN_THREAD_GUARD;
 	if (fsr_sharpness == p_fsr_sharpness) {
 	if (fsr_sharpness == p_fsr_sharpness) {
 		return;
 		return;
 	}
 	}
@@ -3903,10 +4033,12 @@ void Viewport::set_fsr_sharpness(float p_fsr_sharpness) {
 }
 }
 
 
 float Viewport::get_fsr_sharpness() const {
 float Viewport::get_fsr_sharpness() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	return fsr_sharpness;
 	return fsr_sharpness;
 }
 }
 
 
 void Viewport::set_texture_mipmap_bias(float p_texture_mipmap_bias) {
 void Viewport::set_texture_mipmap_bias(float p_texture_mipmap_bias) {
+	ERR_MAIN_THREAD_GUARD;
 	if (texture_mipmap_bias == p_texture_mipmap_bias) {
 	if (texture_mipmap_bias == p_texture_mipmap_bias) {
 		return;
 		return;
 	}
 	}
@@ -3916,6 +4048,7 @@ void Viewport::set_texture_mipmap_bias(float p_texture_mipmap_bias) {
 }
 }
 
 
 float Viewport::get_texture_mipmap_bias() const {
 float Viewport::get_texture_mipmap_bias() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	return texture_mipmap_bias;
 	return texture_mipmap_bias;
 }
 }
 
 
@@ -4309,10 +4442,12 @@ Viewport::~Viewport() {
 /////////////////////////////////
 /////////////////////////////////
 
 
 void SubViewport::set_size(const Size2i &p_size) {
 void SubViewport::set_size(const Size2i &p_size) {
+	ERR_MAIN_THREAD_GUARD;
 	_internal_set_size(p_size);
 	_internal_set_size(p_size);
 }
 }
 
 
 void SubViewport::set_size_force(const Size2i &p_size) {
 void SubViewport::set_size_force(const Size2i &p_size) {
+	ERR_MAIN_THREAD_GUARD;
 	// Use only for setting the size from the parent SubViewportContainer with enabled stretch mode.
 	// Use only for setting the size from the parent SubViewportContainer with enabled stretch mode.
 	// Don't expose function to scripting.
 	// Don't expose function to scripting.
 	_internal_set_size(p_size, true);
 	_internal_set_size(p_size, true);
@@ -4335,18 +4470,22 @@ void SubViewport::_internal_set_size(const Size2i &p_size, bool p_force) {
 }
 }
 
 
 Size2i SubViewport::get_size() const {
 Size2i SubViewport::get_size() const {
+	ERR_READ_THREAD_GUARD_V(Size2());
 	return _get_size();
 	return _get_size();
 }
 }
 
 
 void SubViewport::set_size_2d_override(const Size2i &p_size) {
 void SubViewport::set_size_2d_override(const Size2i &p_size) {
+	ERR_MAIN_THREAD_GUARD;
 	_set_size(_get_size(), p_size, true);
 	_set_size(_get_size(), p_size, true);
 }
 }
 
 
 Size2i SubViewport::get_size_2d_override() const {
 Size2i SubViewport::get_size_2d_override() const {
+	ERR_READ_THREAD_GUARD_V(Size2i());
 	return _get_size_2d_override();
 	return _get_size_2d_override();
 }
 }
 
 
 void SubViewport::set_size_2d_override_stretch(bool p_enable) {
 void SubViewport::set_size_2d_override_stretch(bool p_enable) {
+	ERR_MAIN_THREAD_GUARD;
 	if (p_enable == size_2d_override_stretch) {
 	if (p_enable == size_2d_override_stretch) {
 		return;
 		return;
 	}
 	}
@@ -4356,32 +4495,39 @@ void SubViewport::set_size_2d_override_stretch(bool p_enable) {
 }
 }
 
 
 bool SubViewport::is_size_2d_override_stretch_enabled() const {
 bool SubViewport::is_size_2d_override_stretch_enabled() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return size_2d_override_stretch;
 	return size_2d_override_stretch;
 }
 }
 
 
 void SubViewport::set_update_mode(UpdateMode p_mode) {
 void SubViewport::set_update_mode(UpdateMode p_mode) {
+	ERR_MAIN_THREAD_GUARD;
 	update_mode = p_mode;
 	update_mode = p_mode;
 	RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::ViewportUpdateMode(p_mode));
 	RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::ViewportUpdateMode(p_mode));
 }
 }
 
 
 SubViewport::UpdateMode SubViewport::get_update_mode() const {
 SubViewport::UpdateMode SubViewport::get_update_mode() const {
+	ERR_READ_THREAD_GUARD_V(UPDATE_DISABLED);
 	return update_mode;
 	return update_mode;
 }
 }
 
 
 void SubViewport::set_clear_mode(ClearMode p_mode) {
 void SubViewport::set_clear_mode(ClearMode p_mode) {
+	ERR_MAIN_THREAD_GUARD;
 	clear_mode = p_mode;
 	clear_mode = p_mode;
 	RS::get_singleton()->viewport_set_clear_mode(get_viewport_rid(), RS::ViewportClearMode(p_mode));
 	RS::get_singleton()->viewport_set_clear_mode(get_viewport_rid(), RS::ViewportClearMode(p_mode));
 }
 }
 
 
 SubViewport::ClearMode SubViewport::get_clear_mode() const {
 SubViewport::ClearMode SubViewport::get_clear_mode() const {
+	ERR_READ_THREAD_GUARD_V(CLEAR_MODE_ALWAYS);
 	return clear_mode;
 	return clear_mode;
 }
 }
 
 
 DisplayServer::WindowID SubViewport::get_window_id() const {
 DisplayServer::WindowID SubViewport::get_window_id() const {
+	ERR_READ_THREAD_GUARD_V(DisplayServer::INVALID_WINDOW_ID);
 	return DisplayServer::INVALID_WINDOW_ID;
 	return DisplayServer::INVALID_WINDOW_ID;
 }
 }
 
 
 Transform2D SubViewport::get_screen_transform_internal(bool p_absolute_position) const {
 Transform2D SubViewport::get_screen_transform_internal(bool p_absolute_position) const {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
 	Transform2D container_transform;
 	Transform2D container_transform;
 	SubViewportContainer *c = Object::cast_to<SubViewportContainer>(get_parent());
 	SubViewportContainer *c = Object::cast_to<SubViewportContainer>(get_parent());
 	if (c) {
 	if (c) {
@@ -4396,6 +4542,7 @@ Transform2D SubViewport::get_screen_transform_internal(bool p_absolute_position)
 }
 }
 
 
 Transform2D SubViewport::get_popup_base_transform() const {
 Transform2D SubViewport::get_popup_base_transform() const {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
 	if (is_embedding_subwindows()) {
 	if (is_embedding_subwindows()) {
 		return Transform2D();
 		return Transform2D();
 	}
 	}
@@ -4411,6 +4558,7 @@ Transform2D SubViewport::get_popup_base_transform() const {
 }
 }
 
 
 void SubViewport::_notification(int p_what) {
 void SubViewport::_notification(int p_what) {
+	ERR_MAIN_THREAD_GUARD;
 	switch (p_what) {
 	switch (p_what) {
 		case NOTIFICATION_ENTER_TREE: {
 		case NOTIFICATION_ENTER_TREE: {
 			RS::get_singleton()->viewport_set_active(get_viewport_rid(), true);
 			RS::get_singleton()->viewport_set_active(get_viewport_rid(), true);

+ 134 - 0
scene/main/window.cpp

@@ -43,6 +43,8 @@
 // Dynamic properties.
 // Dynamic properties.
 
 
 bool Window::_set(const StringName &p_name, const Variant &p_value) {
 bool Window::_set(const StringName &p_name, const Variant &p_value) {
+	ERR_MAIN_THREAD_GUARD_V(false);
+
 	String name = p_name;
 	String name = p_name;
 	if (!name.begins_with("theme_override")) {
 	if (!name.begins_with("theme_override")) {
 		return false;
 		return false;
@@ -113,6 +115,8 @@ bool Window::_set(const StringName &p_name, const Variant &p_value) {
 }
 }
 
 
 bool Window::_get(const StringName &p_name, Variant &r_ret) const {
 bool Window::_get(const StringName &p_name, Variant &r_ret) const {
+	ERR_READ_THREAD_GUARD_V(false);
+
 	String sname = p_name;
 	String sname = p_name;
 	if (!sname.begins_with("theme_override")) {
 	if (!sname.begins_with("theme_override")) {
 		return false;
 		return false;
@@ -144,6 +148,8 @@ bool Window::_get(const StringName &p_name, Variant &r_ret) const {
 }
 }
 
 
 void Window::_get_property_list(List<PropertyInfo> *p_list) const {
 void Window::_get_property_list(List<PropertyInfo> *p_list) const {
+	ERR_READ_THREAD_GUARD;
+
 	Ref<Theme> default_theme = ThemeDB::get_singleton()->get_default_theme();
 	Ref<Theme> default_theme = ThemeDB::get_singleton()->get_default_theme();
 
 
 	p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Theme Overrides", "theme_override_"), PROPERTY_HINT_NONE, "theme_override_", PROPERTY_USAGE_GROUP));
 	p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Theme Overrides", "theme_override_"), PROPERTY_HINT_NONE, "theme_override_", PROPERTY_USAGE_GROUP));
@@ -261,6 +267,8 @@ void Window::_validate_property(PropertyInfo &p_property) const {
 //
 //
 
 
 void Window::set_title(const String &p_title) {
 void Window::set_title(const String &p_title) {
+	ERR_MAIN_THREAD_GUARD;
+
 	title = p_title;
 	title = p_title;
 
 
 	if (embedder) {
 	if (embedder) {
@@ -280,19 +288,25 @@ void Window::set_title(const String &p_title) {
 }
 }
 
 
 String Window::get_title() const {
 String Window::get_title() const {
+	ERR_READ_THREAD_GUARD_V(String());
 	return title;
 	return title;
 }
 }
 
 
 void Window::set_initial_position(Window::WindowInitialPosition p_initial_position) {
 void Window::set_initial_position(Window::WindowInitialPosition p_initial_position) {
+	ERR_MAIN_THREAD_GUARD;
+
 	initial_position = p_initial_position;
 	initial_position = p_initial_position;
 	notify_property_list_changed();
 	notify_property_list_changed();
 }
 }
 
 
 Window::WindowInitialPosition Window::get_initial_position() const {
 Window::WindowInitialPosition Window::get_initial_position() const {
+	ERR_READ_THREAD_GUARD_V(WINDOW_INITIAL_POSITION_ABSOLUTE);
 	return initial_position;
 	return initial_position;
 }
 }
 
 
 void Window::set_current_screen(int p_screen) {
 void Window::set_current_screen(int p_screen) {
+	ERR_MAIN_THREAD_GUARD;
+
 	current_screen = p_screen;
 	current_screen = p_screen;
 	if (window_id == DisplayServer::INVALID_WINDOW_ID) {
 	if (window_id == DisplayServer::INVALID_WINDOW_ID) {
 		return;
 		return;
@@ -301,6 +315,8 @@ void Window::set_current_screen(int p_screen) {
 }
 }
 
 
 int Window::get_current_screen() const {
 int Window::get_current_screen() const {
+	ERR_READ_THREAD_GUARD_V(0);
+
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 		current_screen = DisplayServer::get_singleton()->window_get_current_screen(window_id);
 		current_screen = DisplayServer::get_singleton()->window_get_current_screen(window_id);
 	}
 	}
@@ -308,6 +324,8 @@ int Window::get_current_screen() const {
 }
 }
 
 
 void Window::set_position(const Point2i &p_position) {
 void Window::set_position(const Point2i &p_position) {
+	ERR_MAIN_THREAD_GUARD;
+
 	position = p_position;
 	position = p_position;
 
 
 	if (embedder) {
 	if (embedder) {
@@ -319,23 +337,30 @@ void Window::set_position(const Point2i &p_position) {
 }
 }
 
 
 Point2i Window::get_position() const {
 Point2i Window::get_position() const {
+	ERR_READ_THREAD_GUARD_V(Point2i());
+
 	return position;
 	return position;
 }
 }
 
 
 void Window::set_size(const Size2i &p_size) {
 void Window::set_size(const Size2i &p_size) {
+	ERR_MAIN_THREAD_GUARD;
+
 	size = p_size;
 	size = p_size;
 	_update_window_size();
 	_update_window_size();
 }
 }
 
 
 Size2i Window::get_size() const {
 Size2i Window::get_size() const {
+	ERR_READ_THREAD_GUARD_V(Size2i());
 	return size;
 	return size;
 }
 }
 
 
 void Window::reset_size() {
 void Window::reset_size() {
+	ERR_MAIN_THREAD_GUARD;
 	set_size(Size2i());
 	set_size(Size2i());
 }
 }
 
 
 Point2i Window::get_position_with_decorations() const {
 Point2i Window::get_position_with_decorations() const {
+	ERR_READ_THREAD_GUARD_V(Point2i());
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 		return DisplayServer::get_singleton()->window_get_position_with_decorations(window_id);
 		return DisplayServer::get_singleton()->window_get_position_with_decorations(window_id);
 	}
 	}
@@ -343,6 +368,7 @@ Point2i Window::get_position_with_decorations() const {
 }
 }
 
 
 Size2i Window::get_size_with_decorations() const {
 Size2i Window::get_size_with_decorations() const {
+	ERR_READ_THREAD_GUARD_V(Size2i());
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 		return DisplayServer::get_singleton()->window_get_size_with_decorations(window_id);
 		return DisplayServer::get_singleton()->window_get_size_with_decorations(window_id);
 	}
 	}
@@ -366,6 +392,7 @@ void Window::_validate_limit_size() {
 }
 }
 
 
 void Window::set_max_size(const Size2i &p_max_size) {
 void Window::set_max_size(const Size2i &p_max_size) {
+	ERR_MAIN_THREAD_GUARD;
 	Size2i max_size_clamped = _clamp_limit_size(p_max_size);
 	Size2i max_size_clamped = _clamp_limit_size(p_max_size);
 	if (max_size == max_size_clamped) {
 	if (max_size == max_size_clamped) {
 		return;
 		return;
@@ -377,10 +404,12 @@ void Window::set_max_size(const Size2i &p_max_size) {
 }
 }
 
 
 Size2i Window::get_max_size() const {
 Size2i Window::get_max_size() const {
+	ERR_READ_THREAD_GUARD_V(Size2i());
 	return max_size;
 	return max_size;
 }
 }
 
 
 void Window::set_min_size(const Size2i &p_min_size) {
 void Window::set_min_size(const Size2i &p_min_size) {
+	ERR_MAIN_THREAD_GUARD;
 	Size2i min_size_clamped = _clamp_limit_size(p_min_size);
 	Size2i min_size_clamped = _clamp_limit_size(p_min_size);
 	if (min_size == min_size_clamped) {
 	if (min_size == min_size_clamped) {
 		return;
 		return;
@@ -392,10 +421,12 @@ void Window::set_min_size(const Size2i &p_min_size) {
 }
 }
 
 
 Size2i Window::get_min_size() const {
 Size2i Window::get_min_size() const {
+	ERR_READ_THREAD_GUARD_V(Size2i());
 	return min_size;
 	return min_size;
 }
 }
 
 
 void Window::set_mode(Mode p_mode) {
 void Window::set_mode(Mode p_mode) {
+	ERR_MAIN_THREAD_GUARD;
 	mode = p_mode;
 	mode = p_mode;
 
 
 	if (embedder) {
 	if (embedder) {
@@ -407,6 +438,7 @@ void Window::set_mode(Mode p_mode) {
 }
 }
 
 
 Window::Mode Window::get_mode() const {
 Window::Mode Window::get_mode() const {
+	ERR_READ_THREAD_GUARD_V(MODE_WINDOWED);
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 		mode = (Mode)DisplayServer::get_singleton()->window_get_mode(window_id);
 		mode = (Mode)DisplayServer::get_singleton()->window_get_mode(window_id);
 	}
 	}
@@ -414,6 +446,7 @@ Window::Mode Window::get_mode() const {
 }
 }
 
 
 void Window::set_flag(Flags p_flag, bool p_enabled) {
 void Window::set_flag(Flags p_flag, bool p_enabled) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_INDEX(p_flag, FLAG_MAX);
 	ERR_FAIL_INDEX(p_flag, FLAG_MAX);
 	flags[p_flag] = p_enabled;
 	flags[p_flag] = p_enabled;
 
 
@@ -428,6 +461,7 @@ void Window::set_flag(Flags p_flag, bool p_enabled) {
 }
 }
 
 
 bool Window::get_flag(Flags p_flag) const {
 bool Window::get_flag(Flags p_flag) const {
+	ERR_READ_THREAD_GUARD_V(false);
 	ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
 	ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 		if (!is_in_edited_scene_root()) {
 		if (!is_in_edited_scene_root()) {
@@ -438,6 +472,7 @@ bool Window::get_flag(Flags p_flag) const {
 }
 }
 
 
 bool Window::is_maximize_allowed() const {
 bool Window::is_maximize_allowed() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 		return DisplayServer::get_singleton()->window_is_maximize_allowed(window_id);
 		return DisplayServer::get_singleton()->window_is_maximize_allowed(window_id);
 	}
 	}
@@ -445,12 +480,14 @@ bool Window::is_maximize_allowed() const {
 }
 }
 
 
 void Window::request_attention() {
 void Window::request_attention() {
+	ERR_MAIN_THREAD_GUARD;
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 		DisplayServer::get_singleton()->window_request_attention(window_id);
 		DisplayServer::get_singleton()->window_request_attention(window_id);
 	}
 	}
 }
 }
 
 
 void Window::move_to_foreground() {
 void Window::move_to_foreground() {
+	ERR_MAIN_THREAD_GUARD;
 	if (embedder) {
 	if (embedder) {
 		embedder->_sub_window_grab_focus(this);
 		embedder->_sub_window_grab_focus(this);
 
 
@@ -460,6 +497,7 @@ void Window::move_to_foreground() {
 }
 }
 
 
 bool Window::can_draw() const {
 bool Window::can_draw() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	if (!is_inside_tree()) {
 	if (!is_inside_tree()) {
 		return false;
 		return false;
 	}
 	}
@@ -471,24 +509,28 @@ bool Window::can_draw() const {
 }
 }
 
 
 void Window::set_ime_active(bool p_active) {
 void Window::set_ime_active(bool p_active) {
+	ERR_MAIN_THREAD_GUARD;
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 		DisplayServer::get_singleton()->window_set_ime_active(p_active, window_id);
 		DisplayServer::get_singleton()->window_set_ime_active(p_active, window_id);
 	}
 	}
 }
 }
 
 
 void Window::set_ime_position(const Point2i &p_pos) {
 void Window::set_ime_position(const Point2i &p_pos) {
+	ERR_MAIN_THREAD_GUARD;
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 	if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 		DisplayServer::get_singleton()->window_set_ime_position(p_pos, window_id);
 		DisplayServer::get_singleton()->window_set_ime_position(p_pos, window_id);
 	}
 	}
 }
 }
 
 
 bool Window::is_embedded() const {
 bool Window::is_embedded() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	ERR_FAIL_COND_V(!is_inside_tree(), false);
 	ERR_FAIL_COND_V(!is_inside_tree(), false);
 
 
 	return get_embedder() != nullptr;
 	return get_embedder() != nullptr;
 }
 }
 
 
 bool Window::is_in_edited_scene_root() const {
 bool Window::is_in_edited_scene_root() const {
+	ERR_READ_THREAD_GUARD_V(false);
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 	return is_part_of_edited_scene();
 	return is_part_of_edited_scene();
 #else
 #else
@@ -680,6 +722,7 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) {
 }
 }
 
 
 void Window::update_mouse_cursor_shape() {
 void Window::update_mouse_cursor_shape() {
+	ERR_MAIN_THREAD_GUARD;
 	// The default shape is set in Viewport::_gui_input_event. To instantly
 	// The default shape is set in Viewport::_gui_input_event. To instantly
 	// see the shape in the viewport we need to trigger a mouse motion event.
 	// see the shape in the viewport we need to trigger a mouse motion event.
 	Ref<InputEventMouseMotion> mm;
 	Ref<InputEventMouseMotion> mm;
@@ -693,14 +736,17 @@ void Window::update_mouse_cursor_shape() {
 }
 }
 
 
 void Window::show() {
 void Window::show() {
+	ERR_MAIN_THREAD_GUARD;
 	set_visible(true);
 	set_visible(true);
 }
 }
 
 
 void Window::hide() {
 void Window::hide() {
+	ERR_MAIN_THREAD_GUARD;
 	set_visible(false);
 	set_visible(false);
 }
 }
 
 
 void Window::set_visible(bool p_visible) {
 void Window::set_visible(bool p_visible) {
+	ERR_MAIN_THREAD_GUARD;
 	if (visible == p_visible) {
 	if (visible == p_visible) {
 		return;
 		return;
 	}
 	}
@@ -816,6 +862,7 @@ void Window::_make_transient() {
 }
 }
 
 
 void Window::set_transient(bool p_transient) {
 void Window::set_transient(bool p_transient) {
+	ERR_MAIN_THREAD_GUARD;
 	if (transient == p_transient) {
 	if (transient == p_transient) {
 		return;
 		return;
 	}
 	}
@@ -834,10 +881,12 @@ void Window::set_transient(bool p_transient) {
 }
 }
 
 
 bool Window::is_transient() const {
 bool Window::is_transient() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return transient;
 	return transient;
 }
 }
 
 
 void Window::set_exclusive(bool p_exclusive) {
 void Window::set_exclusive(bool p_exclusive) {
+	ERR_MAIN_THREAD_GUARD;
 	if (exclusive == p_exclusive) {
 	if (exclusive == p_exclusive) {
 		return;
 		return;
 	}
 	}
@@ -867,10 +916,12 @@ void Window::set_exclusive(bool p_exclusive) {
 }
 }
 
 
 bool Window::is_exclusive() const {
 bool Window::is_exclusive() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return exclusive;
 	return exclusive;
 }
 }
 
 
 bool Window::is_visible() const {
 bool Window::is_visible() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return visible;
 	return visible;
 }
 }
 
 
@@ -1061,6 +1112,7 @@ void Window::_update_window_callbacks() {
 }
 }
 
 
 Viewport *Window::get_embedder() const {
 Viewport *Window::get_embedder() const {
+	ERR_READ_THREAD_GUARD_V(nullptr);
 	Viewport *vp = get_parent_viewport();
 	Viewport *vp = get_parent_viewport();
 
 
 	while (vp) {
 	while (vp) {
@@ -1078,6 +1130,7 @@ Viewport *Window::get_embedder() const {
 }
 }
 
 
 void Window::_notification(int p_what) {
 void Window::_notification(int p_what) {
+	ERR_MAIN_THREAD_GUARD;
 	switch (p_what) {
 	switch (p_what) {
 		case NOTIFICATION_POSTINITIALIZE: {
 		case NOTIFICATION_POSTINITIALIZE: {
 			initialized = true;
 			initialized = true;
@@ -1215,6 +1268,7 @@ void Window::_notification(int p_what) {
 }
 }
 
 
 void Window::set_content_scale_size(const Size2i &p_size) {
 void Window::set_content_scale_size(const Size2i &p_size) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_COND(p_size.x < 0);
 	ERR_FAIL_COND(p_size.x < 0);
 	ERR_FAIL_COND(p_size.y < 0);
 	ERR_FAIL_COND(p_size.y < 0);
 	content_scale_size = p_size;
 	content_scale_size = p_size;
@@ -1222,38 +1276,46 @@ void Window::set_content_scale_size(const Size2i &p_size) {
 }
 }
 
 
 Size2i Window::get_content_scale_size() const {
 Size2i Window::get_content_scale_size() const {
+	ERR_READ_THREAD_GUARD_V(Size2i());
 	return content_scale_size;
 	return content_scale_size;
 }
 }
 
 
 void Window::set_content_scale_mode(ContentScaleMode p_mode) {
 void Window::set_content_scale_mode(ContentScaleMode p_mode) {
+	ERR_MAIN_THREAD_GUARD;
 	content_scale_mode = p_mode;
 	content_scale_mode = p_mode;
 	_update_viewport_size();
 	_update_viewport_size();
 }
 }
 
 
 Window::ContentScaleMode Window::get_content_scale_mode() const {
 Window::ContentScaleMode Window::get_content_scale_mode() const {
+	ERR_READ_THREAD_GUARD_V(CONTENT_SCALE_MODE_DISABLED);
 	return content_scale_mode;
 	return content_scale_mode;
 }
 }
 
 
 void Window::set_content_scale_aspect(ContentScaleAspect p_aspect) {
 void Window::set_content_scale_aspect(ContentScaleAspect p_aspect) {
+	ERR_MAIN_THREAD_GUARD;
 	content_scale_aspect = p_aspect;
 	content_scale_aspect = p_aspect;
 	_update_viewport_size();
 	_update_viewport_size();
 }
 }
 
 
 Window::ContentScaleAspect Window::get_content_scale_aspect() const {
 Window::ContentScaleAspect Window::get_content_scale_aspect() const {
+	ERR_READ_THREAD_GUARD_V(CONTENT_SCALE_ASPECT_IGNORE);
 	return content_scale_aspect;
 	return content_scale_aspect;
 }
 }
 
 
 void Window::set_content_scale_factor(real_t p_factor) {
 void Window::set_content_scale_factor(real_t p_factor) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_COND(p_factor <= 0);
 	ERR_FAIL_COND(p_factor <= 0);
 	content_scale_factor = p_factor;
 	content_scale_factor = p_factor;
 	_update_viewport_size();
 	_update_viewport_size();
 }
 }
 
 
 real_t Window::get_content_scale_factor() const {
 real_t Window::get_content_scale_factor() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	return content_scale_factor;
 	return content_scale_factor;
 }
 }
 
 
 void Window::set_use_font_oversampling(bool p_oversampling) {
 void Window::set_use_font_oversampling(bool p_oversampling) {
+	ERR_MAIN_THREAD_GUARD;
 	if (is_inside_tree() && window_id != DisplayServer::MAIN_WINDOW_ID) {
 	if (is_inside_tree() && window_id != DisplayServer::MAIN_WINDOW_ID) {
 		ERR_FAIL_MSG("Only the root window can set and use font oversampling.");
 		ERR_FAIL_MSG("Only the root window can set and use font oversampling.");
 	}
 	}
@@ -1262,10 +1324,12 @@ void Window::set_use_font_oversampling(bool p_oversampling) {
 }
 }
 
 
 bool Window::is_using_font_oversampling() const {
 bool Window::is_using_font_oversampling() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return use_font_oversampling;
 	return use_font_oversampling;
 }
 }
 
 
 DisplayServer::WindowID Window::get_window_id() const {
 DisplayServer::WindowID Window::get_window_id() const {
+	ERR_READ_THREAD_GUARD_V(DisplayServer::INVALID_WINDOW_ID);
 	if (embedder) {
 	if (embedder) {
 		return parent->get_window_id();
 		return parent->get_window_id();
 	}
 	}
@@ -1273,6 +1337,7 @@ DisplayServer::WindowID Window::get_window_id() const {
 }
 }
 
 
 void Window::set_mouse_passthrough_polygon(const Vector<Vector2> &p_region) {
 void Window::set_mouse_passthrough_polygon(const Vector<Vector2> &p_region) {
+	ERR_MAIN_THREAD_GUARD;
 	mpath = p_region;
 	mpath = p_region;
 	if (window_id == DisplayServer::INVALID_WINDOW_ID) {
 	if (window_id == DisplayServer::INVALID_WINDOW_ID) {
 		return;
 		return;
@@ -1285,6 +1350,7 @@ Vector<Vector2> Window::get_mouse_passthrough_polygon() const {
 }
 }
 
 
 void Window::set_wrap_controls(bool p_enable) {
 void Window::set_wrap_controls(bool p_enable) {
+	ERR_MAIN_THREAD_GUARD;
 	wrap_controls = p_enable;
 	wrap_controls = p_enable;
 
 
 	if (!is_inside_tree()) {
 	if (!is_inside_tree()) {
@@ -1299,6 +1365,7 @@ void Window::set_wrap_controls(bool p_enable) {
 }
 }
 
 
 bool Window::is_wrapping_controls() const {
 bool Window::is_wrapping_controls() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return wrap_controls;
 	return wrap_controls;
 }
 }
 
 
@@ -1320,6 +1387,7 @@ Size2 Window::_get_contents_minimum_size() const {
 }
 }
 
 
 void Window::child_controls_changed() {
 void Window::child_controls_changed() {
+	ERR_MAIN_THREAD_GUARD;
 	if (!is_inside_tree() || !visible || updating_child_controls) {
 	if (!is_inside_tree() || !visible || updating_child_controls) {
 		return;
 		return;
 	}
 	}
@@ -1397,6 +1465,7 @@ void Window::_window_drop_files(const Vector<String> &p_files) {
 }
 }
 
 
 Viewport *Window::get_parent_viewport() const {
 Viewport *Window::get_parent_viewport() const {
+	ERR_READ_THREAD_GUARD_V(nullptr);
 	if (get_parent()) {
 	if (get_parent()) {
 		return get_parent()->get_viewport();
 		return get_parent()->get_viewport();
 	} else {
 	} else {
@@ -1405,6 +1474,7 @@ Viewport *Window::get_parent_viewport() const {
 }
 }
 
 
 Window *Window::get_parent_visible_window() const {
 Window *Window::get_parent_visible_window() const {
+	ERR_READ_THREAD_GUARD_V(nullptr);
 	Viewport *vp = get_parent_viewport();
 	Viewport *vp = get_parent_viewport();
 	Window *window = nullptr;
 	Window *window = nullptr;
 	while (vp) {
 	while (vp) {
@@ -1422,6 +1492,7 @@ Window *Window::get_parent_visible_window() const {
 }
 }
 
 
 void Window::popup_on_parent(const Rect2i &p_parent_rect) {
 void Window::popup_on_parent(const Rect2i &p_parent_rect) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_COND(!is_inside_tree());
 	ERR_FAIL_COND(!is_inside_tree());
 	ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
 	ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
 
 
@@ -1439,6 +1510,7 @@ void Window::popup_on_parent(const Rect2i &p_parent_rect) {
 }
 }
 
 
 void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio) {
 void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_COND(!is_inside_tree());
 	ERR_FAIL_COND(!is_inside_tree());
 	ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
 	ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
 
 
@@ -1470,6 +1542,7 @@ void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio
 }
 }
 
 
 void Window::popup_centered(const Size2i &p_minsize) {
 void Window::popup_centered(const Size2i &p_minsize) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_COND(!is_inside_tree());
 	ERR_FAIL_COND(!is_inside_tree());
 	ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
 	ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
 
 
@@ -1498,6 +1571,7 @@ void Window::popup_centered(const Size2i &p_minsize) {
 }
 }
 
 
 void Window::popup_centered_ratio(float p_ratio) {
 void Window::popup_centered_ratio(float p_ratio) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_COND(!is_inside_tree());
 	ERR_FAIL_COND(!is_inside_tree());
 	ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
 	ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window.");
 	ERR_FAIL_COND_MSG(p_ratio <= 0.0 || p_ratio > 1.0, "Ratio must be between 0.0 and 1.0!");
 	ERR_FAIL_COND_MSG(p_ratio <= 0.0 || p_ratio > 1.0, "Ratio must be between 0.0 and 1.0!");
@@ -1524,6 +1598,7 @@ void Window::popup_centered_ratio(float p_ratio) {
 }
 }
 
 
 void Window::popup(const Rect2i &p_screen_rect) {
 void Window::popup(const Rect2i &p_screen_rect) {
+	ERR_MAIN_THREAD_GUARD;
 	emit_signal(SNAME("about_to_popup"));
 	emit_signal(SNAME("about_to_popup"));
 
 
 	if (!get_embedder() && get_flag(FLAG_POPUP)) {
 	if (!get_embedder() && get_flag(FLAG_POPUP)) {
@@ -1582,6 +1657,7 @@ void Window::popup(const Rect2i &p_screen_rect) {
 }
 }
 
 
 Rect2i Window::fit_rect_in_parent(Rect2i p_rect, const Rect2i &p_parent_rect) const {
 Rect2i Window::fit_rect_in_parent(Rect2i p_rect, const Rect2i &p_parent_rect) const {
+	ERR_READ_THREAD_GUARD_V(Rect2i());
 	Size2i limit = p_parent_rect.size;
 	Size2i limit = p_parent_rect.size;
 	if (p_rect.position.x + p_rect.size.x > limit.x) {
 	if (p_rect.position.x + p_rect.size.x > limit.x) {
 		p_rect.position.x = limit.x - p_rect.size.x;
 		p_rect.position.x = limit.x - p_rect.size.x;
@@ -1604,10 +1680,12 @@ Rect2i Window::fit_rect_in_parent(Rect2i p_rect, const Rect2i &p_parent_rect) co
 }
 }
 
 
 Size2 Window::get_contents_minimum_size() const {
 Size2 Window::get_contents_minimum_size() const {
+	ERR_READ_THREAD_GUARD_V(Size2());
 	return _get_contents_minimum_size();
 	return _get_contents_minimum_size();
 }
 }
 
 
 Size2 Window::get_clamped_minimum_size() const {
 Size2 Window::get_clamped_minimum_size() const {
+	ERR_READ_THREAD_GUARD_V(Size2());
 	if (!wrap_controls) {
 	if (!wrap_controls) {
 		return min_size;
 		return min_size;
 	}
 	}
@@ -1616,6 +1694,7 @@ Size2 Window::get_clamped_minimum_size() const {
 }
 }
 
 
 void Window::grab_focus() {
 void Window::grab_focus() {
+	ERR_MAIN_THREAD_GUARD;
 	if (embedder) {
 	if (embedder) {
 		embedder->_sub_window_grab_focus(this);
 		embedder->_sub_window_grab_focus(this);
 	} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
 	} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
@@ -1624,10 +1703,12 @@ void Window::grab_focus() {
 }
 }
 
 
 bool Window::has_focus() const {
 bool Window::has_focus() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return focused;
 	return focused;
 }
 }
 
 
 Rect2i Window::get_usable_parent_rect() const {
 Rect2i Window::get_usable_parent_rect() const {
+	ERR_READ_THREAD_GUARD_V(Rect2i());
 	ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
 	ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
 	Rect2i parent_rect;
 	Rect2i parent_rect;
 	if (is_embedded()) {
 	if (is_embedded()) {
@@ -1657,18 +1738,22 @@ void Window::remove_child_notify(Node *p_child) {
 // Theming.
 // Theming.
 
 
 void Window::set_theme_owner_node(Node *p_node) {
 void Window::set_theme_owner_node(Node *p_node) {
+	ERR_MAIN_THREAD_GUARD;
 	theme_owner->set_owner_node(p_node);
 	theme_owner->set_owner_node(p_node);
 }
 }
 
 
 Node *Window::get_theme_owner_node() const {
 Node *Window::get_theme_owner_node() const {
+	ERR_READ_THREAD_GUARD_V(nullptr);
 	return theme_owner->get_owner_node();
 	return theme_owner->get_owner_node();
 }
 }
 
 
 bool Window::has_theme_owner_node() const {
 bool Window::has_theme_owner_node() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return theme_owner->has_owner_node();
 	return theme_owner->has_owner_node();
 }
 }
 
 
 void Window::set_theme(const Ref<Theme> &p_theme) {
 void Window::set_theme(const Ref<Theme> &p_theme) {
+	ERR_MAIN_THREAD_GUARD;
 	if (theme == p_theme) {
 	if (theme == p_theme) {
 		return;
 		return;
 	}
 	}
@@ -1700,6 +1785,7 @@ void Window::set_theme(const Ref<Theme> &p_theme) {
 }
 }
 
 
 Ref<Theme> Window::get_theme() const {
 Ref<Theme> Window::get_theme() const {
+	ERR_READ_THREAD_GUARD_V(Ref<Theme>());
 	return theme;
 	return theme;
 }
 }
 
 
@@ -1748,6 +1834,7 @@ void Window::_update_embedded_window() {
 }
 }
 
 
 void Window::set_theme_type_variation(const StringName &p_theme_type) {
 void Window::set_theme_type_variation(const StringName &p_theme_type) {
+	ERR_MAIN_THREAD_GUARD;
 	theme_type_variation = p_theme_type;
 	theme_type_variation = p_theme_type;
 	if (is_inside_tree()) {
 	if (is_inside_tree()) {
 		notification(NOTIFICATION_THEME_CHANGED);
 		notification(NOTIFICATION_THEME_CHANGED);
@@ -1755,12 +1842,14 @@ void Window::set_theme_type_variation(const StringName &p_theme_type) {
 }
 }
 
 
 StringName Window::get_theme_type_variation() const {
 StringName Window::get_theme_type_variation() const {
+	ERR_READ_THREAD_GUARD_V(StringName());
 	return theme_type_variation;
 	return theme_type_variation;
 }
 }
 
 
 /// Theme property lookup.
 /// Theme property lookup.
 
 
 Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
 Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
+	ERR_READ_THREAD_GUARD_V(Ref<Texture2D>());
 	if (!initialized) {
 	if (!initialized) {
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 	}
 	}
@@ -1784,6 +1873,7 @@ Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName
 }
 }
 
 
 Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
 Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
+	ERR_READ_THREAD_GUARD_V(Ref<StyleBox>());
 	if (!initialized) {
 	if (!initialized) {
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 	}
 	}
@@ -1807,6 +1897,7 @@ Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringN
 }
 }
 
 
 Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
 Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
+	ERR_READ_THREAD_GUARD_V(Ref<Font>());
 	if (!initialized) {
 	if (!initialized) {
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 	}
 	}
@@ -1830,6 +1921,7 @@ Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_t
 }
 }
 
 
 int Window::get_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
 int Window::get_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
+	ERR_READ_THREAD_GUARD_V(0);
 	if (!initialized) {
 	if (!initialized) {
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 	}
 	}
@@ -1853,6 +1945,7 @@ int Window::get_theme_font_size(const StringName &p_name, const StringName &p_th
 }
 }
 
 
 Color Window::get_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
 Color Window::get_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
+	ERR_READ_THREAD_GUARD_V(Color());
 	if (!initialized) {
 	if (!initialized) {
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 	}
 	}
@@ -1876,6 +1969,7 @@ Color Window::get_theme_color(const StringName &p_name, const StringName &p_them
 }
 }
 
 
 int Window::get_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
 int Window::get_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
+	ERR_READ_THREAD_GUARD_V(0);
 	if (!initialized) {
 	if (!initialized) {
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 	}
 	}
@@ -1899,6 +1993,7 @@ int Window::get_theme_constant(const StringName &p_name, const StringName &p_the
 }
 }
 
 
 bool Window::has_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
 bool Window::has_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
+	ERR_READ_THREAD_GUARD_V(false);
 	if (!initialized) {
 	if (!initialized) {
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 	}
 	}
@@ -1915,6 +2010,7 @@ bool Window::has_theme_icon(const StringName &p_name, const StringName &p_theme_
 }
 }
 
 
 bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
 bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
+	ERR_READ_THREAD_GUARD_V(false);
 	if (!initialized) {
 	if (!initialized) {
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 	}
 	}
@@ -1931,6 +2027,7 @@ bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_th
 }
 }
 
 
 bool Window::has_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
 bool Window::has_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
+	ERR_READ_THREAD_GUARD_V(false);
 	if (!initialized) {
 	if (!initialized) {
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 	}
 	}
@@ -1947,6 +2044,7 @@ bool Window::has_theme_font(const StringName &p_name, const StringName &p_theme_
 }
 }
 
 
 bool Window::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
 bool Window::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
+	ERR_READ_THREAD_GUARD_V(false);
 	if (!initialized) {
 	if (!initialized) {
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 	}
 	}
@@ -1963,6 +2061,7 @@ bool Window::has_theme_font_size(const StringName &p_name, const StringName &p_t
 }
 }
 
 
 bool Window::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
 bool Window::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
+	ERR_READ_THREAD_GUARD_V(false);
 	if (!initialized) {
 	if (!initialized) {
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 	}
 	}
@@ -1979,6 +2078,7 @@ bool Window::has_theme_color(const StringName &p_name, const StringName &p_theme
 }
 }
 
 
 bool Window::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
 bool Window::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
+	ERR_READ_THREAD_GUARD_V(false);
 	if (!initialized) {
 	if (!initialized) {
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 		WARN_PRINT_ONCE("Attempting to access theme items too early; prefer NOTIFICATION_POSTINITIALIZE and NOTIFICATION_THEME_CHANGED");
 	}
 	}
@@ -1997,6 +2097,7 @@ bool Window::has_theme_constant(const StringName &p_name, const StringName &p_th
 /// Local property overrides.
 /// Local property overrides.
 
 
 void Window::add_theme_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon) {
 void Window::add_theme_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_COND(!p_icon.is_valid());
 	ERR_FAIL_COND(!p_icon.is_valid());
 
 
 	if (theme_icon_override.has(p_name)) {
 	if (theme_icon_override.has(p_name)) {
@@ -2009,6 +2110,7 @@ void Window::add_theme_icon_override(const StringName &p_name, const Ref<Texture
 }
 }
 
 
 void Window::add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) {
 void Window::add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_COND(!p_style.is_valid());
 	ERR_FAIL_COND(!p_style.is_valid());
 
 
 	if (theme_style_override.has(p_name)) {
 	if (theme_style_override.has(p_name)) {
@@ -2021,6 +2123,7 @@ void Window::add_theme_style_override(const StringName &p_name, const Ref<StyleB
 }
 }
 
 
 void Window::add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font) {
 void Window::add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_COND(!p_font.is_valid());
 	ERR_FAIL_COND(!p_font.is_valid());
 
 
 	if (theme_font_override.has(p_name)) {
 	if (theme_font_override.has(p_name)) {
@@ -2033,21 +2136,25 @@ void Window::add_theme_font_override(const StringName &p_name, const Ref<Font> &
 }
 }
 
 
 void Window::add_theme_font_size_override(const StringName &p_name, int p_font_size) {
 void Window::add_theme_font_size_override(const StringName &p_name, int p_font_size) {
+	ERR_MAIN_THREAD_GUARD;
 	theme_font_size_override[p_name] = p_font_size;
 	theme_font_size_override[p_name] = p_font_size;
 	_notify_theme_override_changed();
 	_notify_theme_override_changed();
 }
 }
 
 
 void Window::add_theme_color_override(const StringName &p_name, const Color &p_color) {
 void Window::add_theme_color_override(const StringName &p_name, const Color &p_color) {
+	ERR_MAIN_THREAD_GUARD;
 	theme_color_override[p_name] = p_color;
 	theme_color_override[p_name] = p_color;
 	_notify_theme_override_changed();
 	_notify_theme_override_changed();
 }
 }
 
 
 void Window::add_theme_constant_override(const StringName &p_name, int p_constant) {
 void Window::add_theme_constant_override(const StringName &p_name, int p_constant) {
+	ERR_MAIN_THREAD_GUARD;
 	theme_constant_override[p_name] = p_constant;
 	theme_constant_override[p_name] = p_constant;
 	_notify_theme_override_changed();
 	_notify_theme_override_changed();
 }
 }
 
 
 void Window::remove_theme_icon_override(const StringName &p_name) {
 void Window::remove_theme_icon_override(const StringName &p_name) {
+	ERR_MAIN_THREAD_GUARD;
 	if (theme_icon_override.has(p_name)) {
 	if (theme_icon_override.has(p_name)) {
 		theme_icon_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
 		theme_icon_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
 	}
 	}
@@ -2057,6 +2164,7 @@ void Window::remove_theme_icon_override(const StringName &p_name) {
 }
 }
 
 
 void Window::remove_theme_style_override(const StringName &p_name) {
 void Window::remove_theme_style_override(const StringName &p_name) {
+	ERR_MAIN_THREAD_GUARD;
 	if (theme_style_override.has(p_name)) {
 	if (theme_style_override.has(p_name)) {
 		theme_style_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
 		theme_style_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
 	}
 	}
@@ -2066,6 +2174,7 @@ void Window::remove_theme_style_override(const StringName &p_name) {
 }
 }
 
 
 void Window::remove_theme_font_override(const StringName &p_name) {
 void Window::remove_theme_font_override(const StringName &p_name) {
+	ERR_MAIN_THREAD_GUARD;
 	if (theme_font_override.has(p_name)) {
 	if (theme_font_override.has(p_name)) {
 		theme_font_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
 		theme_font_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed));
 	}
 	}
@@ -2075,46 +2184,55 @@ void Window::remove_theme_font_override(const StringName &p_name) {
 }
 }
 
 
 void Window::remove_theme_font_size_override(const StringName &p_name) {
 void Window::remove_theme_font_size_override(const StringName &p_name) {
+	ERR_MAIN_THREAD_GUARD;
 	theme_font_size_override.erase(p_name);
 	theme_font_size_override.erase(p_name);
 	_notify_theme_override_changed();
 	_notify_theme_override_changed();
 }
 }
 
 
 void Window::remove_theme_color_override(const StringName &p_name) {
 void Window::remove_theme_color_override(const StringName &p_name) {
+	ERR_MAIN_THREAD_GUARD;
 	theme_color_override.erase(p_name);
 	theme_color_override.erase(p_name);
 	_notify_theme_override_changed();
 	_notify_theme_override_changed();
 }
 }
 
 
 void Window::remove_theme_constant_override(const StringName &p_name) {
 void Window::remove_theme_constant_override(const StringName &p_name) {
+	ERR_MAIN_THREAD_GUARD;
 	theme_constant_override.erase(p_name);
 	theme_constant_override.erase(p_name);
 	_notify_theme_override_changed();
 	_notify_theme_override_changed();
 }
 }
 
 
 bool Window::has_theme_icon_override(const StringName &p_name) const {
 bool Window::has_theme_icon_override(const StringName &p_name) const {
+	ERR_READ_THREAD_GUARD_V(false);
 	const Ref<Texture2D> *tex = theme_icon_override.getptr(p_name);
 	const Ref<Texture2D> *tex = theme_icon_override.getptr(p_name);
 	return tex != nullptr;
 	return tex != nullptr;
 }
 }
 
 
 bool Window::has_theme_stylebox_override(const StringName &p_name) const {
 bool Window::has_theme_stylebox_override(const StringName &p_name) const {
+	ERR_READ_THREAD_GUARD_V(false);
 	const Ref<StyleBox> *style = theme_style_override.getptr(p_name);
 	const Ref<StyleBox> *style = theme_style_override.getptr(p_name);
 	return style != nullptr;
 	return style != nullptr;
 }
 }
 
 
 bool Window::has_theme_font_override(const StringName &p_name) const {
 bool Window::has_theme_font_override(const StringName &p_name) const {
+	ERR_READ_THREAD_GUARD_V(false);
 	const Ref<Font> *font = theme_font_override.getptr(p_name);
 	const Ref<Font> *font = theme_font_override.getptr(p_name);
 	return font != nullptr;
 	return font != nullptr;
 }
 }
 
 
 bool Window::has_theme_font_size_override(const StringName &p_name) const {
 bool Window::has_theme_font_size_override(const StringName &p_name) const {
+	ERR_READ_THREAD_GUARD_V(false);
 	const int *font_size = theme_font_size_override.getptr(p_name);
 	const int *font_size = theme_font_size_override.getptr(p_name);
 	return font_size != nullptr;
 	return font_size != nullptr;
 }
 }
 
 
 bool Window::has_theme_color_override(const StringName &p_name) const {
 bool Window::has_theme_color_override(const StringName &p_name) const {
+	ERR_READ_THREAD_GUARD_V(false);
 	const Color *color = theme_color_override.getptr(p_name);
 	const Color *color = theme_color_override.getptr(p_name);
 	return color != nullptr;
 	return color != nullptr;
 }
 }
 
 
 bool Window::has_theme_constant_override(const StringName &p_name) const {
 bool Window::has_theme_constant_override(const StringName &p_name) const {
+	ERR_READ_THREAD_GUARD_V(false);
 	const int *constant = theme_constant_override.getptr(p_name);
 	const int *constant = theme_constant_override.getptr(p_name);
 	return constant != nullptr;
 	return constant != nullptr;
 }
 }
@@ -2122,24 +2240,29 @@ bool Window::has_theme_constant_override(const StringName &p_name) const {
 /// Default theme properties.
 /// Default theme properties.
 
 
 float Window::get_theme_default_base_scale() const {
 float Window::get_theme_default_base_scale() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	return theme_owner->get_theme_default_base_scale();
 	return theme_owner->get_theme_default_base_scale();
 }
 }
 
 
 Ref<Font> Window::get_theme_default_font() const {
 Ref<Font> Window::get_theme_default_font() const {
+	ERR_READ_THREAD_GUARD_V(Ref<Font>());
 	return theme_owner->get_theme_default_font();
 	return theme_owner->get_theme_default_font();
 }
 }
 
 
 int Window::get_theme_default_font_size() const {
 int Window::get_theme_default_font_size() const {
+	ERR_READ_THREAD_GUARD_V(0);
 	return theme_owner->get_theme_default_font_size();
 	return theme_owner->get_theme_default_font_size();
 }
 }
 
 
 /// Bulk actions.
 /// Bulk actions.
 
 
 void Window::begin_bulk_theme_override() {
 void Window::begin_bulk_theme_override() {
+	ERR_MAIN_THREAD_GUARD;
 	bulk_theme_override = true;
 	bulk_theme_override = true;
 }
 }
 
 
 void Window::end_bulk_theme_override() {
 void Window::end_bulk_theme_override() {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_COND(!bulk_theme_override);
 	ERR_FAIL_COND(!bulk_theme_override);
 
 
 	bulk_theme_override = false;
 	bulk_theme_override = false;
@@ -2149,6 +2272,7 @@ void Window::end_bulk_theme_override() {
 //
 //
 
 
 Rect2i Window::get_parent_rect() const {
 Rect2i Window::get_parent_rect() const {
+	ERR_READ_THREAD_GUARD_V(Rect2i());
 	ERR_FAIL_COND_V(!is_inside_tree(), Rect2i());
 	ERR_FAIL_COND_V(!is_inside_tree(), Rect2i());
 	if (is_embedded()) {
 	if (is_embedded()) {
 		//viewport
 		//viewport
@@ -2185,14 +2309,17 @@ Rect2i Window::get_parent_rect() const {
 }
 }
 
 
 void Window::set_clamp_to_embedder(bool p_enable) {
 void Window::set_clamp_to_embedder(bool p_enable) {
+	ERR_MAIN_THREAD_GUARD;
 	clamp_to_embedder = p_enable;
 	clamp_to_embedder = p_enable;
 }
 }
 
 
 bool Window::is_clamped_to_embedder() const {
 bool Window::is_clamped_to_embedder() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return clamp_to_embedder;
 	return clamp_to_embedder;
 }
 }
 
 
 void Window::set_layout_direction(Window::LayoutDirection p_direction) {
 void Window::set_layout_direction(Window::LayoutDirection p_direction) {
+	ERR_MAIN_THREAD_GUARD;
 	ERR_FAIL_INDEX((int)p_direction, 4);
 	ERR_FAIL_INDEX((int)p_direction, 4);
 
 
 	layout_dir = p_direction;
 	layout_dir = p_direction;
@@ -2200,10 +2327,12 @@ void Window::set_layout_direction(Window::LayoutDirection p_direction) {
 }
 }
 
 
 Window::LayoutDirection Window::get_layout_direction() const {
 Window::LayoutDirection Window::get_layout_direction() const {
+	ERR_READ_THREAD_GUARD_V(LAYOUT_DIRECTION_INHERITED);
 	return layout_dir;
 	return layout_dir;
 }
 }
 
 
 bool Window::is_layout_rtl() const {
 bool Window::is_layout_rtl() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	if (layout_dir == LAYOUT_DIRECTION_INHERITED) {
 	if (layout_dir == LAYOUT_DIRECTION_INHERITED) {
 		if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) {
 		if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) {
 			return true;
 			return true;
@@ -2244,6 +2373,7 @@ bool Window::is_layout_rtl() const {
 }
 }
 
 
 void Window::set_auto_translate(bool p_enable) {
 void Window::set_auto_translate(bool p_enable) {
+	ERR_MAIN_THREAD_GUARD;
 	if (p_enable == auto_translate) {
 	if (p_enable == auto_translate) {
 		return;
 		return;
 	}
 	}
@@ -2254,14 +2384,17 @@ void Window::set_auto_translate(bool p_enable) {
 }
 }
 
 
 bool Window::is_auto_translating() const {
 bool Window::is_auto_translating() const {
+	ERR_READ_THREAD_GUARD_V(false);
 	return auto_translate;
 	return auto_translate;
 }
 }
 
 
 Transform2D Window::get_final_transform() const {
 Transform2D Window::get_final_transform() const {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
 	return window_transform * stretch_transform * global_canvas_transform;
 	return window_transform * stretch_transform * global_canvas_transform;
 }
 }
 
 
 Transform2D Window::get_screen_transform_internal(bool p_absolute_position) const {
 Transform2D Window::get_screen_transform_internal(bool p_absolute_position) const {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
 	Transform2D embedder_transform;
 	Transform2D embedder_transform;
 	if (get_embedder()) {
 	if (get_embedder()) {
 		embedder_transform.translate_local(get_position());
 		embedder_transform.translate_local(get_position());
@@ -2273,6 +2406,7 @@ Transform2D Window::get_screen_transform_internal(bool p_absolute_position) cons
 }
 }
 
 
 Transform2D Window::get_popup_base_transform() const {
 Transform2D Window::get_popup_base_transform() const {
+	ERR_READ_THREAD_GUARD_V(Transform2D());
 	if (is_embedding_subwindows()) {
 	if (is_embedding_subwindows()) {
 		return Transform2D();
 		return Transform2D();
 	}
 	}

Some files were not shown because too many files changed in this diff