Browse Source

Merge pull request #60531 from lawnjelly/fti_usage_warnings

Rémi Verschelde 3 years ago
parent
commit
4cfc96fea7

+ 4 - 0
doc/classes/ProjectSettings.xml

@@ -414,6 +414,10 @@
 		<member name="debug/settings/gdscript/max_call_stack" type="int" setter="" getter="" default="1024">
 			Maximum call stack allowed for debugging GDScript.
 		</member>
+		<member name="debug/settings/physics_interpolation/enable_warnings" type="bool" setter="" getter="" default="true">
+			If [code]true[/code], enables warnings which can help pinpoint where nodes are being incorrectly updated, which will result in incorrect interpolation and visual glitches.
+			When a node is being interpolated, it is essential that the transform is set during [method Node._physics_process] (during a physics tick) rather than [method Node._process] (during a frame).
+		</member>
 		<member name="debug/settings/profiler/max_functions" type="int" setter="" getter="" default="16384">
 			Maximum amount of functions per frame allowed when profiling.
 		</member>

+ 2 - 0
main/main.cpp

@@ -1224,6 +1224,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
 	GLOBAL_DEF("debug/settings/stdout/print_fps", false);
 	GLOBAL_DEF("debug/settings/stdout/verbose_stdout", false);
 
+	GLOBAL_DEF("debug/settings/physics_interpolation/enable_warnings", true);
+
 	if (!OS::get_singleton()->_verbose_stdout) { // Not manually overridden.
 		OS::get_singleton()->_verbose_stdout = GLOBAL_GET("debug/settings/stdout/verbose_stdout");
 	}

+ 32 - 0
servers/visual/rasterizer.cpp

@@ -33,6 +33,10 @@
 #include "core/os/os.h"
 #include "core/print_string.h"
 
+#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
+#include "core/project_settings.h"
+#endif
+
 Rasterizer *(*Rasterizer::_create_func)() = nullptr;
 
 Rasterizer *Rasterizer::create() {
@@ -350,6 +354,16 @@ void RasterizerStorage::multimesh_instance_set_transform(RID p_multimesh, int p_
 			ptr[11] = t.origin.z;
 
 			_multimesh_add_to_interpolation_lists(p_multimesh, *mmi);
+
+#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
+			if (!Engine::get_singleton()->is_in_physics_frame()) {
+				static int32_t warn_count = 0;
+				warn_count++;
+				if (((warn_count % 2048) == 0) && GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
+					WARN_PRINT("Interpolated MultiMesh transform should usually be set during physics process (possibly benign).");
+				}
+			}
+#endif
 			return;
 		}
 	}
@@ -498,6 +512,15 @@ void RasterizerStorage::multimesh_set_as_bulk_array_interpolated(RID p_multimesh
 		mmi->_data_prev = p_array_prev;
 		mmi->_data_curr = p_array;
 		_multimesh_add_to_interpolation_lists(p_multimesh, *mmi);
+#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
+		if (!Engine::get_singleton()->is_in_physics_frame()) {
+			static int32_t warn_count = 0;
+			warn_count++;
+			if (((warn_count % 2048) == 0) && GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
+				WARN_PRINT("Interpolated MultiMesh transform should usually be set during physics process (possibly benign).");
+			}
+		}
+#endif
 	}
 }
 
@@ -507,6 +530,15 @@ void RasterizerStorage::multimesh_set_as_bulk_array(RID p_multimesh, const PoolV
 		if (mmi->interpolated) {
 			mmi->_data_curr = p_array;
 			_multimesh_add_to_interpolation_lists(p_multimesh, *mmi);
+#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
+			if (!Engine::get_singleton()->is_in_physics_frame()) {
+				static int32_t warn_count = 0;
+				warn_count++;
+				if (((warn_count % 2048) == 0) && GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
+					WARN_PRINT("Interpolated MultiMesh transform should usually be set during physics process (possibly benign).");
+				}
+			}
+#endif
 			return;
 		}
 	}

+ 77 - 7
servers/visual/visual_server_scene.cpp

@@ -103,14 +103,37 @@ void VisualServerScene::camera_set_transform(RID p_camera, const Transform &p_tr
 
 	camera->transform = p_transform.orthonormalized();
 
-	if (_interpolation_data.interpolation_enabled && camera->interpolated) {
-		if (!camera->on_interpolate_transform_list) {
-			_interpolation_data.camera_transform_update_list_curr->push_back(p_camera);
-			camera->on_interpolate_transform_list = true;
-		}
+	if (_interpolation_data.interpolation_enabled) {
+		if (camera->interpolated) {
+			if (!camera->on_interpolate_transform_list) {
+				_interpolation_data.camera_transform_update_list_curr->push_back(p_camera);
+				camera->on_interpolate_transform_list = true;
+			}
+
+			// decide on the interpolation method .. slerp if possible
+			camera->interpolation_method = TransformInterpolator::find_method(camera->transform_prev.basis, camera->transform.basis);
 
-		// decide on the interpolation method .. slerp if possible
-		camera->interpolation_method = TransformInterpolator::find_method(camera->transform_prev.basis, camera->transform.basis);
+#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
+			if (!Engine::get_singleton()->is_in_physics_frame()) {
+				// Effectively a WARN_PRINT_ONCE but after a certain number of occurrences.
+				static int32_t warn_count = -256;
+				if ((warn_count == 0) && GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
+					WARN_PRINT("Interpolated Camera transform should usually be set during physics process (possibly benign).");
+				}
+				warn_count++;
+			}
+#endif
+		} else {
+#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
+			if (Engine::get_singleton()->is_in_physics_frame()) {
+				static int32_t warn_count = -256;
+				if ((warn_count == 0) && GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
+					WARN_PRINT("Non-interpolated Camera transform should not usually be set during physics process (possibly benign).");
+				}
+				warn_count++;
+			}
+#endif
+		}
 	}
 }
 
@@ -808,6 +831,30 @@ void VisualServerScene::instance_set_transform(RID p_instance, const Transform &
 #endif
 		instance->transform = p_transform;
 		_instance_queue_update(instance, true);
+
+#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
+		if ((_interpolation_data.interpolation_enabled && !instance->interpolated) && (Engine::get_singleton()->is_in_physics_frame())) {
+			static int32_t warn_count = 0;
+			warn_count++;
+			if (((warn_count % 2048) == 0) && GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
+				String node_name;
+				ObjectID id = instance->object_id;
+				if (id != 0) {
+					if (ObjectDB::get_instance(id)) {
+						Node *node = Object::cast_to<Node>(ObjectDB::get_instance(id));
+						if (node) {
+							node_name = "\"" + node->get_name() + "\"";
+						} else {
+							node_name = "\"unknown\"";
+						}
+					}
+				}
+
+				WARN_PRINT("Non-interpolated Instance " + node_name + " transform should usually not be set during physics process (possibly benign).");
+			}
+		}
+#endif
+
 		return;
 	}
 
@@ -861,6 +908,29 @@ void VisualServerScene::instance_set_transform(RID p_instance, const Transform &
 	}
 
 	_instance_queue_update(instance, true);
+
+#if defined(DEBUG_ENABLED) && defined(TOOLS_ENABLED)
+	if (!Engine::get_singleton()->is_in_physics_frame()) {
+		static int32_t warn_count = 0;
+		warn_count++;
+		if (((warn_count % 2048) == 0) && GLOBAL_GET("debug/settings/physics_interpolation/enable_warnings")) {
+			String node_name;
+			ObjectID id = instance->object_id;
+			if (id != 0) {
+				if (ObjectDB::get_instance(id)) {
+					Node *node = Object::cast_to<Node>(ObjectDB::get_instance(id));
+					if (node) {
+						node_name = "\"" + node->get_name() + "\"";
+					} else {
+						node_name = "\"unknown\"";
+					}
+				}
+			}
+
+			WARN_PRINT("Interpolated Instance " + node_name + " transform should usually be set during physics process (possibly benign).");
+		}
+	}
+#endif
 }
 
 void VisualServerScene::InterpolationData::notify_free_camera(RID p_rid, Camera &r_camera) {