From d41445fb4bbc9064919e2bce137b6a1456000432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akan=20Sidenvall?= Date: Tue, 18 Nov 2025 18:21:43 +0100 Subject: [PATCH 1/8] FIX: Workaround for ISX-1766 to reduce memory allocations from reflective type loading to only happen when an unresolved type is encountered in an input action asset. --- .../InputSystem/InputManager.cs | 13 ++++++++++--- .../InputSystem/Utilities/TypeTable.cs | 10 +++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/InputManager.cs b/Packages/com.unity.inputsystem/InputSystem/InputManager.cs index 30649e5269..01d314d939 100644 --- a/Packages/com.unity.inputsystem/InputSystem/InputManager.cs +++ b/Packages/com.unity.inputsystem/InputSystem/InputManager.cs @@ -2026,8 +2026,8 @@ internal void InitializeData() composites.AddTypeRegistration("OneModifier", typeof(OneModifierComposite)); composites.AddTypeRegistration("TwoModifiers", typeof(TwoModifiersComposite)); - // Register custom types by reflection - RegisterCustomTypes(); + // ISXB-1766: Defer loading custom types by reflection unless we have to since referenced from + // .inputaction JSON assets. This is managed via TypeTable.cs. } void RegisterCustomTypes(Type[] types) @@ -2053,8 +2053,13 @@ void RegisterCustomTypes(Type[] types) } } - void RegisterCustomTypes() + internal bool hasCustomTypesBeenRegistered { get; private set; } + + internal void RegisterCustomTypes() { + if (hasCustomTypesBeenRegistered) + return; + k_InputRegisterCustomTypesMarker.Begin(); var inputSystemAssembly = typeof(InputProcessor).Assembly; @@ -2084,6 +2089,8 @@ void RegisterCustomTypes() } k_InputRegisterCustomTypesMarker.End(); + + hasCustomTypesBeenRegistered = true; } internal void InstallRuntime(IInputRuntime runtime) diff --git a/Packages/com.unity.inputsystem/InputSystem/Utilities/TypeTable.cs b/Packages/com.unity.inputsystem/InputSystem/Utilities/TypeTable.cs index 4120bdce88..4f56a87e25 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Utilities/TypeTable.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Utilities/TypeTable.cs @@ -83,7 +83,15 @@ public Type LookupTypeRegistration(string name) var internedName = new InternedString(name); if (table.TryGetValue(internedName, out var type)) return type; - return null; + + // Failed to look-up type, either type do not exist or it is a custom type. + // Check whether we have attempted to load custom types and otherwise lazily load + // types only when referenced and reattempt looking up type by name. (ISXB-1766) + if (InputSystem.s_Manager == null || InputSystem.s_Manager.hasCustomTypesBeenRegistered) + return null; + + InputSystem.s_Manager.RegisterCustomTypes(); + return LookupTypeRegistration(name); } #if UNITY_EDITOR From 4b229a29e461a12e0a28dbce0512989c1ff2a684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akan=20Sidenvall?= Date: Tue, 18 Nov 2025 20:07:40 +0100 Subject: [PATCH 2/8] Moved boolean condition to make sure its set even if exception is thrown --- Packages/com.unity.inputsystem/InputSystem/InputManager.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/InputManager.cs b/Packages/com.unity.inputsystem/InputSystem/InputManager.cs index 01d314d939..4daaf925cf 100644 --- a/Packages/com.unity.inputsystem/InputSystem/InputManager.cs +++ b/Packages/com.unity.inputsystem/InputSystem/InputManager.cs @@ -2059,6 +2059,7 @@ internal void RegisterCustomTypes() { if (hasCustomTypesBeenRegistered) return; + hasCustomTypesBeenRegistered = true; k_InputRegisterCustomTypesMarker.Begin(); @@ -2089,8 +2090,6 @@ internal void RegisterCustomTypes() } k_InputRegisterCustomTypesMarker.End(); - - hasCustomTypesBeenRegistered = true; } internal void InstallRuntime(IInputRuntime runtime) From 5cb4617686c194acc18850eca639f4460a594dcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akan=20Sidenvall?= Date: Tue, 18 Nov 2025 23:04:19 +0100 Subject: [PATCH 3/8] Changed TypeTable to be tightly coupled to an InputManager instance. Removed property that could be internal to InputManager and be returned as method result instead. --- .../InputSystem/InputManager.cs | 28 ++++++++++++------- .../InputSystem/Utilities/TypeTable.cs | 24 +++++++++++----- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/InputManager.cs b/Packages/com.unity.inputsystem/InputSystem/InputManager.cs index 4daaf925cf..ae48929f23 100644 --- a/Packages/com.unity.inputsystem/InputSystem/InputManager.cs +++ b/Packages/com.unity.inputsystem/InputSystem/InputManager.cs @@ -1858,6 +1858,7 @@ internal void Initialize(IInputRuntime runtime, InputSettings settings) Debug.Assert(settings != null); m_Settings = settings; + m_LazyLoadCustomTypes = () => RegisterCustomTypes(); // Cached delegate InitializeActions(); InitializeData(); @@ -1913,9 +1914,9 @@ private void InitializeActions() internal void InitializeData() { m_Layouts.Allocate(); - m_Processors.Initialize(); - m_Interactions.Initialize(); - m_Composites.Initialize(); + m_Processors.Initialize(this); + m_Interactions.Initialize(this); + m_Composites.Initialize(this); m_DevicesById = new Dictionary(); // Determine our default set of enabled update types. By @@ -2030,7 +2031,7 @@ internal void InitializeData() // .inputaction JSON assets. This is managed via TypeTable.cs. } - void RegisterCustomTypes(Type[] types) + static void RegisterCustomTypes(Type[] types) { foreach (Type type in types) { @@ -2053,13 +2054,17 @@ void RegisterCustomTypes(Type[] types) } } - internal bool hasCustomTypesBeenRegistered { get; private set; } + private bool m_CustomTypesRegistered; - internal void RegisterCustomTypes() + internal bool RegisterCustomTypes() { - if (hasCustomTypesBeenRegistered) - return; - hasCustomTypesBeenRegistered = true; + // If we have already attempted to register custom types, there is no need to reattempt since we + // would end up with the same result again. Only with a domain reload would the resulting types + // be different, and hence it is sufficient to use a static flag that we do not reset. + if (!m_CustomTypesRegistered) + return false; + + m_CustomTypesRegistered = true; k_InputRegisterCustomTypesMarker.Begin(); @@ -2085,11 +2090,13 @@ internal void RegisterCustomTypes() } catch (ReflectionTypeLoadException) { - continue; + // Ignore exception } } k_InputRegisterCustomTypesMarker.End(); + + return true; } internal void InstallRuntime(IInputRuntime runtime) @@ -2270,6 +2277,7 @@ internal struct AvailableDevice internal IInputRuntime m_Runtime; internal InputMetrics m_Metrics; internal InputSettings m_Settings; + private Func m_LazyLoadCustomTypes; // Extract as booleans (from m_Settings) because feature check is in the hot path diff --git a/Packages/com.unity.inputsystem/InputSystem/Utilities/TypeTable.cs b/Packages/com.unity.inputsystem/InputSystem/Utilities/TypeTable.cs index 4f56a87e25..d543408e90 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Utilities/TypeTable.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Utilities/TypeTable.cs @@ -25,12 +25,16 @@ internal struct TypeTable public HashSet aliases; #endif - public void Initialize() + // Strong coupling to Input Manager which is always the owner + private InputManager m_Manager; + + public void Initialize(InputManager manager) { table = new Dictionary(); #if UNITY_EDITOR aliases = new HashSet(); #endif + m_Manager = manager; } public InternedString FindNameForType(Type type) @@ -80,18 +84,24 @@ public Type LookupTypeRegistration(string name) if (table == null) throw new InvalidOperationException("Input System not yet initialized"); - var internedName = new InternedString(name); + return TryLookupTypeRegistration(new InternedString(name)); + } + + private Type TryLookupTypeRegistration(InternedString internedName) + { if (table.TryGetValue(internedName, out var type)) return type; - // Failed to look-up type, either type do not exist or it is a custom type. + // Failed to look-up type, either type do not exist or it is a custom type that has not been registered. // Check whether we have attempted to load custom types and otherwise lazily load // types only when referenced and reattempt looking up type by name. (ISXB-1766) - if (InputSystem.s_Manager == null || InputSystem.s_Manager.hasCustomTypesBeenRegistered) - return null; + if (m_Manager != null) + { + if (m_Manager.RegisterCustomTypes()) + return TryLookupTypeRegistration(internedName); // Recursive call + } - InputSystem.s_Manager.RegisterCustomTypes(); - return LookupTypeRegistration(name); + return null; } #if UNITY_EDITOR From 858f1b7d1e0a86c7143d9f5727af27f82ae694eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akan=20Sidenvall?= Date: Tue, 18 Nov 2025 23:12:09 +0100 Subject: [PATCH 4/8] Reset type registration when uninstalling globals to cause side-effects between InputManager instances. --- Packages/com.unity.inputsystem/InputSystem/InputManager.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/InputManager.cs b/Packages/com.unity.inputsystem/InputSystem/InputManager.cs index ae48929f23..5b7c431045 100644 --- a/Packages/com.unity.inputsystem/InputSystem/InputManager.cs +++ b/Packages/com.unity.inputsystem/InputSystem/InputManager.cs @@ -2177,6 +2177,9 @@ internal void UninstallGlobals() InputControlLayout.s_CacheInstance = default; InputControlLayout.s_CacheInstanceRef = 0; + // Invalidate type registrations + m_CustomTypesRegistered = false; + // Detach from runtime. if (m_Runtime != null) { @@ -2277,7 +2280,6 @@ internal struct AvailableDevice internal IInputRuntime m_Runtime; internal InputMetrics m_Metrics; internal InputSettings m_Settings; - private Func m_LazyLoadCustomTypes; // Extract as booleans (from m_Settings) because feature check is in the hot path From 7c2cac7bb3412bc892336b87484787b15cc56111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akan=20Sidenvall?= Date: Tue, 18 Nov 2025 23:18:02 +0100 Subject: [PATCH 5/8] Code cleanup. --- Packages/com.unity.inputsystem/InputSystem/InputManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/InputManager.cs b/Packages/com.unity.inputsystem/InputSystem/InputManager.cs index 5b7c431045..398712263f 100644 --- a/Packages/com.unity.inputsystem/InputSystem/InputManager.cs +++ b/Packages/com.unity.inputsystem/InputSystem/InputManager.cs @@ -1858,7 +1858,6 @@ internal void Initialize(IInputRuntime runtime, InputSettings settings) Debug.Assert(settings != null); m_Settings = settings; - m_LazyLoadCustomTypes = () => RegisterCustomTypes(); // Cached delegate InitializeActions(); InitializeData(); From dd3c8676738339e2f501bba833f1f15b4b518267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akan=20Sidenvall?= Date: Wed, 19 Nov 2025 08:46:57 +0100 Subject: [PATCH 6/8] Corrected incorrect if statement. --- Packages/com.unity.inputsystem/InputSystem/InputManager.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/InputManager.cs b/Packages/com.unity.inputsystem/InputSystem/InputManager.cs index 398712263f..947bd044a9 100644 --- a/Packages/com.unity.inputsystem/InputSystem/InputManager.cs +++ b/Packages/com.unity.inputsystem/InputSystem/InputManager.cs @@ -2060,8 +2060,8 @@ internal bool RegisterCustomTypes() // If we have already attempted to register custom types, there is no need to reattempt since we // would end up with the same result again. Only with a domain reload would the resulting types // be different, and hence it is sufficient to use a static flag that we do not reset. - if (!m_CustomTypesRegistered) - return false; + if (m_CustomTypesRegistered) + return false; // Already evaluated m_CustomTypesRegistered = true; @@ -2095,7 +2095,7 @@ internal bool RegisterCustomTypes() k_InputRegisterCustomTypesMarker.End(); - return true; + return true; // Signal that custom types were extracted and registered. } internal void InstallRuntime(IInputRuntime runtime) From 5f2fe5cc16f985b2f39be2ebd648564cffb833f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akan=20Sidenvall?= Date: Wed, 19 Nov 2025 08:52:33 +0100 Subject: [PATCH 7/8] Simplified code and removed recursive call. --- .../InputSystem/Utilities/TypeTable.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Packages/com.unity.inputsystem/InputSystem/Utilities/TypeTable.cs b/Packages/com.unity.inputsystem/InputSystem/Utilities/TypeTable.cs index d543408e90..009740d344 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Utilities/TypeTable.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Utilities/TypeTable.cs @@ -89,19 +89,19 @@ public Type LookupTypeRegistration(string name) private Type TryLookupTypeRegistration(InternedString internedName) { - if (table.TryGetValue(internedName, out var type)) - return type; - - // Failed to look-up type, either type do not exist or it is a custom type that has not been registered. - // Check whether we have attempted to load custom types and otherwise lazily load - // types only when referenced and reattempt looking up type by name. (ISXB-1766) - if (m_Manager != null) + if (!table.TryGetValue(internedName, out var type)) { - if (m_Manager.RegisterCustomTypes()) - return TryLookupTypeRegistration(internedName); // Recursive call + // Failed to look-up type, either type do not exist or it is a custom type that has not been registered. + // Check whether we have attempted to load custom types and otherwise lazily load types only when + // relevant and reattempt looking up type by name. (ISXB-1766) + if (m_Manager != null) + { + if (m_Manager.RegisterCustomTypes()) + table.TryGetValue(internedName, out type); + } } - return null; + return type; } #if UNITY_EDITOR From f611a2ddedf656a9e7e7fd260b676dbdc45ce6c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=CC=8Akan=20Sidenvall?= Date: Wed, 19 Nov 2025 08:58:12 +0100 Subject: [PATCH 8/8] Updated CHANGELOG.md --- Packages/com.unity.inputsystem/CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Packages/com.unity.inputsystem/CHANGELOG.md b/Packages/com.unity.inputsystem/CHANGELOG.md index 21cddde19e..446a823257 100644 --- a/Packages/com.unity.inputsystem/CHANGELOG.md +++ b/Packages/com.unity.inputsystem/CHANGELOG.md @@ -18,7 +18,9 @@ however, it has to be formatted properly to pass verification tests. ### Fixed - An issue where a UITK MouseEvent was triggered when changing from Scene View to Game View in the Editor has been fixed. [ISXB-1671](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1671) - Fix documentation error in file AndroidGameController.cs mentioning a wrong controller. [DOCATT-9806] - +- Deferred auto-registration of processors, interactions and composite binding types referenced by `InputActionAsset` + to only happen once when an unresolved type reference is found in an action definition. This avoids reflective + type loading from assemblies for all cases where the Input System is not extended. (ISXB-1766). ## [1.16.0] - 2025-11-10