Mouse events such as MouseMove and MouseDrag gets piled up, preventing editor views from repainting and dedicating resources to more important things such as actually rendering the scene. In some cases it takes 30+ calls to render a single frame, taking up most of the resources in order to render pretty much nothing. (see images below).
I think this explains why newer versions of Unity feels kind of laggy compared to older onces. For a while, I thought it was just the garbage collector or random Unity hiccups, but at least part of the problem is that mouse movements causes the editor to lag.
I’m not sure when this started happening but tried it in 5.3 and the most I could get out of it there was: “Layout, MouseMove, Layout, MouseMove, Layout, Repaint.” I’d guess it was introduced in Unity 2018 or late 2017, not entirely sure.
I’m running Unity 2018.3.0f2 on Windows, with a 144hz and 60hz monitor, and a semi high mouse DPI, and a polling rate of 1ms.
I made a small debugging utility to demonstrate the issue, here are some screenshots showing the issue. The code snippet for the utility is down below as well.
It’s also interesting to see that if I pretend to do a lot of work (Thread.Sleep(13)). It doesn’t pile nearly as many events up during a frame, which means some sort filtering is already happening but it would be great if it could be improved!
Event Counter Script
using System.Collections.Generic;
using System.Threading;
using UnityEditor;
using UnityEngine;
public class EventCrazyness : EditorWindow
{
private bool pause = false;
private int sleep = 1;
private EventDebugger eventDebugger;
[MenuItem("Bug/Test")]
static void Open()
{
var wnd = CreateInstance<EventCrazyness>();
wnd.Show();
}
private void OnEnable()
{
this.wantsMouseMove = true;
}
private void OnGUI()
{
this.eventDebugger = this.eventDebugger ?? new EventDebugger();
Thread.Sleep(this.sleep);
EditorGUIUtility.labelWidth = 300;
this.pause = EditorGUILayout.Toggle("Pause", this.pause);
this.wantsMouseMove = EditorGUILayout.Toggle("Wans Mouse Move", this.wantsMouseMove);
this.sleep = EditorGUILayout.IntSlider("Simulate Inspector Work (sleep time in ms)", this.sleep, 0, 20);
GUILayout.Space(20);
this.eventDebugger.Draw();
this.Repaint();
if (!this.pause)
{
this.eventDebugger.Update();
}
if (Event.current.type == EventType.MouseDown && Event.current.button == 1)
{
this.pause = !this.pause;
}
}
}
public static class SceneViewDebugger
{
private static EventDebugger eventDebugger;
[InitializeOnLoadMethod]
public static void Init()
{
SceneView.onSceneGUIDelegate += DRAW;
}
private static void DRAW(SceneView sceneView)
{
eventDebugger = eventDebugger ?? new EventDebugger();
SceneView.RepaintAll();
Handles.BeginGUI();
GUILayout.BeginArea(new Rect(0, 0, 10000, 1000));
eventDebugger.Draw();
eventDebugger.Update();
GUILayout.EndArea();
Handles.EndGUI();
}
}
public class EventDebugger
{
private EventFrame currentFrame = new EventFrame();
private List<EventFrame> frames = new List<EventFrame>();
public void Draw()
{
for (int i = this.frames.Count - 1; i >= 0; i--)
{
this.frames[i].Draw();
}
}
public void Update()
{
if (Event.current.type == EventType.Repaint)
{
this.currentFrame.EventTypes.Add("<color=green>" + Event.current.type + "</color>");
}
else
{
this.currentFrame.EventTypes.Add(Event.current.type + "");
}
if (Event.current.type == EventType.Repaint)
{
this.currentFrame.DeltaTime = EditorApplication.timeSinceStartup - this.currentFrame.DeltaTime;
this.frames.Add(this.currentFrame);
if (this.frames.Count > 30)
{
this.frames.RemoveAt(0);
}
this.currentFrame = new EventFrame();
this.currentFrame.DeltaTime = EditorApplication.timeSinceStartup;
}
}
}
public class EventFrame
{
private static GUIStyle multiText = new GUIStyle(GUI.skin.label) { richText = true, fontSize = 9 };
public double DeltaTime;
public List<string> EventTypes = new List<string>();
public void Draw()
{
var fps = this.DeltaTime <= 0 ? 0 : (1 / this.DeltaTime);
GUILayout.Label("<color=red>FPS</color>: " + (int)fps + ", <color=red>Frame</color>: " + string.Join(", ", this.EventTypes), multiText);
}
}
Edit:
Lowering the polling rate does help a lot! It is still firing way more events than necessary imo. It’s an easy optimization to make and will make the editor feel much smoother on a lot of PC’s!
Here it is at a polling rate of 125 hz
And already at 250hz it starts looking like this:
It’s confirm as well by the fokes over on this thread, with examples and more information: Unity stutters and hitches even in empty scenes, Unreal does not
Edit2:
Bug reported: https://fogbugz.unity3d.com/default.asp?1117360_0gofd5off8lcd2ub