From a98ef213fffbdef929482df29b58a7c8e611aa75 Mon Sep 17 00:00:00 2001 From: bd_ Date: Tue, 17 Sep 2024 23:25:47 -0400 Subject: [PATCH] fix: performance issues with MAMenuItem (#1170) Cache parameter introspection results (using PropCache) to avoid excessive recomputation. Closes: #1165 --- Editor/Inspector/Menu/MenuItemGUI.cs | 43 +++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/Editor/Inspector/Menu/MenuItemGUI.cs b/Editor/Inspector/Menu/MenuItemGUI.cs index 67458e40..29c75b63 100644 --- a/Editor/Inspector/Menu/MenuItemGUI.cs +++ b/Editor/Inspector/Menu/MenuItemGUI.cs @@ -2,10 +2,12 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Runtime.Serialization; using nadena.dev.modular_avatar.core.menu; using nadena.dev.ndmf; +using nadena.dev.ndmf.preview; using UnityEditor; using UnityEngine; using VRC.SDK3.Avatars.Components; @@ -21,6 +23,39 @@ namespace nadena.dev.modular_avatar.core.editor protected override string localizationPrefix => "submenu_source"; } + internal static class ParameterIntrospectionCache + { + internal static PropCache> ProvidedParameterCache = new (GetParametersForObject_miss); + + internal static PropCache> + ParameterRemappingCache = new(GetParameterRemappingsAt_miss); + + private static ImmutableList GetParametersForObject_miss(ComputeContext ctx, GameObject obj) + { + if (obj == null) return ImmutableList.Empty; + + return ParameterInfo.ForPreview(ctx).GetParametersForObject(obj).ToImmutableList(); + } + + private static ImmutableDictionary<(ParameterNamespace, string), ParameterMapping> + GetParameterRemappingsAt_miss(ComputeContext ctx, GameObject obj) + { + if (obj == null) return ImmutableDictionary<(ParameterNamespace, string), ParameterMapping>.Empty; + + return ParameterInfo.ForPreview(ctx).GetParameterRemappingsAt(obj); + } + + internal static ImmutableList GetParametersForObject(GameObject avatar) + { + return ProvidedParameterCache.Get(ComputeContext.NullContext, avatar); + } + + internal static ImmutableDictionary<(ParameterNamespace, string), ParameterMapping> GetParameterRemappingsAt(GameObject avatar) + { + return ParameterRemappingCache.Get(ComputeContext.NullContext, avatar); + } + } + internal class MenuItemCoreGUI { private static readonly ObjectIDGenerator IdGenerator = new ObjectIDGenerator(); @@ -134,12 +169,12 @@ namespace nadena.dev.modular_avatar.core.editor Dictionary rootParameters = new(); - foreach (var param in ParameterInfo.ForUI.GetParametersForObject(parentAvatar.gameObject) + foreach (var param in ParameterIntrospectionCache.GetParametersForObject(parentAvatar.gameObject) .Where(p => p.Namespace == ParameterNamespace.Animator) ) rootParameters[param.EffectiveName] = param; - var remaps = ParameterInfo.ForUI.GetParameterRemappingsAt(paramRef); + var remaps = ParameterIntrospectionCache.GetParameterRemappingsAt(paramRef); foreach (var remap in remaps) { if (remap.Key.Item1 != ParameterNamespace.Animator) continue; @@ -613,7 +648,7 @@ namespace nadena.dev.modular_avatar.core.editor var myParameterName = myMenuItem.Control.parameter.name; if (string.IsNullOrEmpty(myParameterName)) return new List(); - var myMappings = ParameterInfo.ForUI.GetParameterRemappingsAt(myMenuItem.gameObject); + var myMappings = ParameterIntrospectionCache.GetParameterRemappingsAt(myMenuItem.gameObject); if (myMappings.TryGetValue((ParameterNamespace.Animator, myParameterName), out var myReplacement)) myParameterName = myReplacement.ParameterName; @@ -627,7 +662,7 @@ namespace nadena.dev.modular_avatar.core.editor var otherParameterName = otherMenuItem.Control.parameter.name; if (string.IsNullOrEmpty(otherParameterName)) continue; - var otherMappings = ParameterInfo.ForUI.GetParameterRemappingsAt(otherMenuItem.gameObject); + var otherMappings = ParameterIntrospectionCache.GetParameterRemappingsAt(otherMenuItem.gameObject); if (otherMappings.TryGetValue((ParameterNamespace.Animator, otherParameterName), out var otherReplacement)) otherParameterName = otherReplacement.ParameterName;