Search Unity

[Editor Lag] Mouse events gets piled up and prevents views from rendering.

Discussion in 'Editor & General Support' started by bjarkeck, Jan 13, 2019.

  1. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    244
    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!

    Editor Lag Scene View.png

    Editor Lag Window.png


    Code (CSharp):
    1. using System.Collections.Generic;
    2. using System.Threading;
    3. using UnityEditor;
    4. using UnityEngine;
    5.  
    6. public class EventCrazyness : EditorWindow
    7. {
    8.     private bool pause = false;
    9.     private int sleep = 1;
    10.     private EventDebugger eventDebugger;
    11.  
    12.     [MenuItem("Bug/Test")]
    13.     static void Open()
    14.     {
    15.         var wnd = CreateInstance<EventCrazyness>();
    16.         wnd.Show();
    17.     }
    18.  
    19.     private void OnEnable()
    20.     {
    21.         this.wantsMouseMove = true;
    22.     }
    23.  
    24.     private void OnGUI()
    25.     {
    26.         this.eventDebugger = this.eventDebugger ?? new EventDebugger();
    27.  
    28.         Thread.Sleep(this.sleep);
    29.  
    30.         EditorGUIUtility.labelWidth = 300;
    31.         this.pause = EditorGUILayout.Toggle("Pause", this.pause);
    32.         this.wantsMouseMove = EditorGUILayout.Toggle("Wans Mouse Move", this.wantsMouseMove);
    33.         this.sleep = EditorGUILayout.IntSlider("Simulate Inspector Work (sleep time in ms)", this.sleep, 0, 20);
    34.         GUILayout.Space(20);
    35.  
    36.         this.eventDebugger.Draw();
    37.         this.Repaint();
    38.  
    39.         if (!this.pause)
    40.         {
    41.             this.eventDebugger.Update();
    42.         }
    43.  
    44.         if (Event.current.type == EventType.MouseDown && Event.current.button == 1)
    45.         {
    46.             this.pause = !this.pause;
    47.         }
    48.     }
    49. }
    50.  
    51. public static class SceneViewDebugger
    52. {
    53.     private static EventDebugger eventDebugger;
    54.  
    55.     [InitializeOnLoadMethod]
    56.     public static void Init()
    57.     {
    58.         SceneView.onSceneGUIDelegate += DRAW;
    59.     }
    60.  
    61.     private static void DRAW(SceneView sceneView)
    62.     {
    63.         eventDebugger = eventDebugger ?? new EventDebugger();
    64.         SceneView.RepaintAll();
    65.         Handles.BeginGUI();
    66.         GUILayout.BeginArea(new Rect(0, 0, 10000, 1000));
    67.         eventDebugger.Draw();
    68.         eventDebugger.Update();
    69.         GUILayout.EndArea();
    70.         Handles.EndGUI();
    71.     }
    72. }
    73.  
    74. public class EventDebugger
    75. {
    76.     private EventFrame currentFrame = new EventFrame();
    77.     private List<EventFrame> frames = new List<EventFrame>();
    78.  
    79.     public void Draw()
    80.     {
    81.         for (int i = this.frames.Count - 1; i >= 0; i--)
    82.         {
    83.             this.frames[i].Draw();
    84.         }
    85.     }
    86.  
    87.     public void Update()
    88.     {
    89.         if (Event.current.type == EventType.Repaint)
    90.         {
    91.             this.currentFrame.EventTypes.Add("<color=green>" + Event.current.type + "</color>");
    92.         }
    93.         else
    94.         {
    95.             this.currentFrame.EventTypes.Add(Event.current.type + "");
    96.         }
    97.  
    98.         if (Event.current.type == EventType.Repaint)
    99.         {
    100.             this.currentFrame.DeltaTime = EditorApplication.timeSinceStartup - this.currentFrame.DeltaTime;
    101.             this.frames.Add(this.currentFrame);
    102.             if (this.frames.Count > 30)
    103.             {
    104.                 this.frames.RemoveAt(0);
    105.             }
    106.             this.currentFrame = new EventFrame();
    107.             this.currentFrame.DeltaTime = EditorApplication.timeSinceStartup;
    108.         }
    109.     }
    110. }
    111.  
    112. public class EventFrame
    113. {
    114.     private static GUIStyle multiText = new GUIStyle(GUI.skin.label) { richText = true, fontSize = 9 };
    115.     public double DeltaTime;
    116.     public List<string> EventTypes = new List<string>();
    117.  
    118.     public void Draw()
    119.     {
    120.         var fps = this.DeltaTime <= 0 ? 0 : (1 / this.DeltaTime);
    121.         GUILayout.Label("<color=red>FPS</color>: " + (int)fps + ", <color=red>Frame</color>: " + string.Join(", ", this.EventTypes), multiText);
    122.     }
    123. }
    124.  

    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
    125hz.png

    And already at 250hz it starts looking like this:
    250hz.png

    It's confirm as well by the fokes over on this thread, with examples and more information: https://forum.unity.com/threads/uni...-even-in-empty-scenes-unreal-does-not.609808/

    Edit2:
    Bug reported: https://fogbugz.unity3d.com/default.asp?1117360_0gofd5off8lcd2ub
     
    Last edited: Jan 15, 2019
  2. Atair

    Atair

    Joined:
    Oct 16, 2015
    Posts:
    42
    Came here to post this (without the sophisticated analysis)
    Here some more info:
    - the editor, especially viewport navigation is laggy / choppy in 2018, didnt have that in 2017
    - i can narrow it down to the mouse dpi: a microsoft intellimouse mouse (the new ones) is lagging
    - using an 10$ low dpi mouse makes viewport navigation smooth again
    - lowering dpi on the new ones is not helping

    Something to add: I experience the same kind of lag in 3ds max with the new intellmouse (on multiple machines, with multiple mice). Now finally i have a better idea of how and why - as this is happening in both programs: The only thing they have in common is using QT?
    At autodesk of course nobody ever responded, i hope this gets better traction here..
     
    Tor-Vestergaard and bjarkeck like this.
  3. rawalanche

    rawalanche

    Joined:
    Aug 26, 2017
    Posts:
    20
    Last edited: Jan 14, 2019
    bjarkeck likes this.