Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Extreme Lag With Material Editor When You Have Lots Of Types In Project 2018.3.12f1

Discussion in 'Editor & General Support' started by Lecht, Apr 14, 2019.

  1. Lecht

    Lecht

    Joined:
    Jul 1, 2014
    Posts:
    24
    So I was using 2018.6 for a while, I noticed there was a lot of lag when trying to view/edit certain material properties. I noticed a fix in 2018.12 that said something a long the lines of "Fixed material editor lag when your project contained a lot of types." So I switched, and it was still very laggy.

    I profiled it, it ended up landing on ShaderGUIUtility.CreateShaderGUI.

    So what happens is CreateShaderGUI calls ExtractCustomEditorType looking for the type, it seems every editor frame? Anyways, the problem is that if the type isn't found, it tries to find it over and over again. Or if the type IS found and doesn't derive from ShaderGUI, in my case it was derived from MaterialEditor, then it also calls it over and over again.

    I'm surprised there's no type of caching going on here to prevent the iteration of all the assemblies and all types in those assemblies every frame.

    I wrote a harmony patch to fix the issue, and wanted to share just in case it was as debilitating for someone else as it was for me.

    Code (CSharp):
    1.  
    2. [HarmonyPatch()]
    3. public class MaterialEditorPatch
    4. {
    5.     private static Type _type;
    6.     private static bool _mouseUp;
    7.  
    8.     static MethodInfo TargetMethod()
    9.     {
    10.         _type = Harmony.AccessTools.TypeByName("UnityEditor.ShaderGUIUtility");
    11.         return _type.GetMethod("ExtractCustomEditorType", AccessTools.all);
    12.     }
    13.  
    14.     static Dictionary<string, Type> _cache = new Dictionary<string, Type>();
    15.    
    16.     static bool Prefix(ref Type __result, ref string customEditorName)
    17.     {
    18.         if (_cache.TryGetValue(customEditorName, out __result))
    19.             return false;
    20.  
    21.         if (string.IsNullOrEmpty(customEditorName))
    22.             return false;
    23.        
    24.         string str = "UnityEditor." + customEditorName;
    25.         Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
    26.        
    27.         for (int i = loadedAssemblies.Length - 1; i >= 0; i--)
    28.         {
    29.             foreach (Type type2 in loadedAssemblies[i].GetTypes())
    30.             {
    31.                 if (!type2.FullName.Equals(customEditorName, StringComparison.Ordinal) &&
    32.                     !type2.FullName.Equals(str, StringComparison.Ordinal))
    33.                     continue;
    34.  
    35.                 if (typeof(ShaderGUI).IsAssignableFrom(type2))
    36.                 {
    37.                     __result = type2;
    38.  
    39.                     _cache.Add(customEditorName, type2);
    40.                     return false;
    41.                 }
    42.  
    43.                 break;
    44.             }
    45.         }
    46.  
    47.         _cache.Add(customEditorName, null);
    48.        
    49.         return false;
    50.     }
    51. }
    52.  
     
    io-games likes this.
  2. io-games

    io-games

    Joined:
    Jun 2, 2016
    Posts:
    95
    Thx for patch. How to apply it?
     
  3. io-games

    io-games

    Joined:
    Jun 2, 2016
    Posts:
    95
    Full code for patching
    also you need to download 0Harmony.dll from github or nuget https://github.com/pardeike/Harmony/releases
    Tested on 2019.1.10f1
    P.S. first time it's slow as before

    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using System.Reflection;
    4. using Harmony;
    5. using UnityEditor;
    6.  
    7. [InitializeOnLoad]
    8. [HarmonyPatch]
    9. public class MaterialEditorPatch
    10. {
    11.     private static Type _type;
    12.     private static bool _mouseUp;
    13.  
    14.     static MaterialEditorPatch()
    15.     {
    16.         Patch();
    17.     }
    18.  
    19.     [MenuItem("Tools/Fix ExtractCustomEditorType")]
    20.     public static void Patch()
    21.     {
    22.         var target = TargetMethod();
    23.         var prefix = typeof(MaterialEditorPatch).GetMethod("Prefix", BindingFlags.NonPublic | BindingFlags.Static);
    24.      
    25.         var harmony = HarmonyInstance.Create("ExtractCustomEditorTypePatch");
    26.      
    27.         harmony.Patch(target, new HarmonyMethod(prefix));
    28.     }
    29.  
    30.  
    31.     static MethodInfo TargetMethod()
    32.     {
    33.         _type = AccessTools.TypeByName("UnityEditor.ShaderGUIUtility");
    34.         return _type.GetMethod("ExtractCustomEditorType", AccessTools.all);
    35.     }
    36.     static Dictionary<string, Type> _cache = new Dictionary<string, Type>();
    37.  
    38.     static bool Prefix(ref Type __result, ref string customEditorName)
    39.     {
    40.         if (_cache.TryGetValue(customEditorName, out __result))
    41.             return false;
    42.         if (string.IsNullOrEmpty(customEditorName))
    43.             return false;
    44.      
    45.         var str = "UnityEditor." + customEditorName;
    46.         Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
    47.      
    48.         for (var i = loadedAssemblies.Length - 1; i >= 0; i--)
    49.         {
    50.             foreach (var type2 in loadedAssemblies[i].GetTypes())
    51.             {
    52.                 if (!type2.FullName.Equals(customEditorName, StringComparison.Ordinal) &&
    53.                     !type2.FullName.Equals(str, StringComparison.Ordinal))
    54.                     continue;
    55.                 if (typeof(ShaderGUI).IsAssignableFrom(type2))
    56.                 {
    57.                     __result = type2;
    58.                     _cache.Add(customEditorName, type2);
    59.                     return false;
    60.                 }
    61.                 break;
    62.             }
    63.         }
    64.         _cache.Add(customEditorName, null);
    65.      
    66.         return false;
    67.     }
    68. }
     
    Last edited: Jul 22, 2019
    Meceka, Pecek and shanecelis like this.
  4. shanecelis

    shanecelis

    Joined:
    Mar 26, 2014
    Posts:
    22
    This patch increased my quality of life. Thank you.
     
  5. Meceka

    Meceka

    Joined:
    Dec 23, 2013
    Posts:
    420
    Hi @io-games , Can you please explain how I should import the 0Harmony.dll file into unity to apply this patch?

    I just imported 0Harmony.dll into the project as in the Assets folder but it's still a missing reference in your MaterialEditorPatch code.

    Thanks
     
  6. io-games

    io-games

    Joined:
    Jun 2, 2016
    Posts:
    95
    https://yadi.sk/d/CZ4acSNIPa4RzA

    put to any Editor folder (create if not exists)
     
    Last edited: May 15, 2020
    Meceka likes this.
  7. Meceka

    Meceka

    Joined:
    Dec 23, 2013
    Posts:
    420
    Thank you but I couldn't download, mega asks for a Decryption Key.
     
  8. io-games

    io-games

    Joined:
    Jun 2, 2016
    Posts:
    95
    Meceka likes this.
  9. Meceka

    Meceka

    Joined:
    Dec 23, 2013
    Posts:
    420
  10. zachlindblad

    zachlindblad

    Joined:
    Sep 29, 2016
    Posts:
    39
    Is there in ticket opened in the unity bug tracker for this issue? I'm unsure if I should hack in a patched dll as @io-games and others are doing or if updating my unity version will resolve this breaking issue in a way that's a bit safer.