diff --git a/Packages/src/Runtime/Internal/ProjectSettings/PreloadedProjectSettings.cs b/Packages/src/Runtime/Internal/ProjectSettings/PreloadedProjectSettings.cs index 24ad435..f2fe8ca 100644 --- a/Packages/src/Runtime/Internal/ProjectSettings/PreloadedProjectSettings.cs +++ b/Packages/src/Runtime/Internal/ProjectSettings/PreloadedProjectSettings.cs @@ -13,13 +13,15 @@ namespace Coffee.UIParticleInternal { public abstract class PreloadedProjectSettings : ScriptableObject #if UNITY_EDITOR - , IPreprocessBuildWithReport { - int IOrderedCallback.callbackOrder => 0; - - void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report) + private class PreprocessBuildWithReport : IPreprocessBuildWithReport { - Initialize(); + int IOrderedCallback.callbackOrder => 0; + + void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report) + { + Initialize(); + } } [InitializeOnLoadMethod] diff --git a/Packages/src/Runtime/Internal/Utilities/Logging.cs b/Packages/src/Runtime/Internal/Utilities/Logging.cs index feee1be..64b7334 100644 --- a/Packages/src/Runtime/Internal/Utilities/Logging.cs +++ b/Packages/src/Runtime/Internal/Utilities/Logging.cs @@ -5,6 +5,7 @@ using Object = UnityEngine.Object; #if ENABLE_COFFEE_LOGGER using System.Reflection; using System.Collections.Generic; + #else using Conditional = System.Diagnostics.ConditionalAttribute; #endif @@ -140,6 +141,9 @@ namespace Coffee.UIParticleInternal switch (tag) { + case string name: + sb.Append(name); + break; case Type type: AppendType(sb, type); break; diff --git a/Packages/src/Runtime/Internal/Utilities/ObjectRepository.cs b/Packages/src/Runtime/Internal/Utilities/ObjectRepository.cs index d6d9ad9..46213cf 100644 --- a/Packages/src/Runtime/Internal/Utilities/ObjectRepository.cs +++ b/Packages/src/Runtime/Internal/Utilities/ObjectRepository.cs @@ -8,10 +8,11 @@ namespace Coffee.UIParticleInternal { internal class ObjectRepository where T : Object { - private readonly List _cache = new List(); + private readonly Dictionary _cache = new Dictionary(8); + private readonly Dictionary _objectKey = new Dictionary(8); private readonly string _name; private readonly Action _onRelease; - private readonly Stack _pool = new Stack(); + private readonly Stack _pool = new Stack(8); public ObjectRepository(Action onRelease = null) { @@ -36,40 +37,33 @@ namespace Coffee.UIParticleInternal { _onRelease = onRelease; } + + for (var i = 0; i < 8; i++) + { + _pool.Push(new Entry()); + } } public int count => _cache.Count; public void Clear() { - for (var i = 0; i < _cache.Count; i++) + foreach (var kv in _cache) { - var entry = _cache[i]; + var entry = kv.Value; if (entry == null) continue; entry.Release(_onRelease); + _pool.Push(entry); } _cache.Clear(); + _objectKey.Clear(); } public bool Valid(Hash128 hash, T obj) { - // Find existing entry. - Profiler.BeginSample("(COF)[ObjectRepository] Valid > Find existing entry"); - for (var i = 0; i < _cache.Count; ++i) - { - var entry = _cache[i]; - if (entry.hash != hash) continue; - Profiler.EndSample(); - - // Existing entry found. - return entry.storedObject == obj; - } - - Profiler.EndSample(); - - return false; + return _cache.TryGetValue(hash, out var entry) && entry.storedObject == obj; } /// @@ -77,41 +71,8 @@ namespace Coffee.UIParticleInternal /// public void Get(Hash128 hash, ref T obj, Func onCreate) { - // Find existing entry. - Profiler.BeginSample("(COF)[ObjectRepository] Get > Find existing entry"); - for (var i = 0; i < _cache.Count; ++i) - { - var entry = _cache[i]; - if (entry.hash != hash) continue; - - // Existing entry found. - if (entry.storedObject != obj) - { - // if the object is different, release the old one. - Release(ref obj); - ++entry.reference; - obj = entry.storedObject; - Logging.Log(_name, $"Get(#{count}): {entry}"); - } - - Profiler.EndSample(); - return; - } - - Profiler.EndSample(); - - // Create new entry. - Profiler.BeginSample("(COF)[ObjectRepository] Get > Create new entry"); - var newEntry = 0 < _pool.Count ? _pool.Pop() : new Entry(); - newEntry.storedObject = onCreate(); - newEntry.hash = hash; - newEntry.reference = 1; - _cache.Add(newEntry); - Logging.Log(_name, $"Get(#{count}): {newEntry}"); - - Release(ref obj); - obj = newEntry.storedObject; - Profiler.EndSample(); + if (GetFromCache(hash, ref obj)) return; + Add(hash, ref obj, onCreate()); } /// @@ -119,40 +80,60 @@ namespace Coffee.UIParticleInternal /// public void Get(Hash128 hash, ref T obj, Func onCreate, TS source) { - // Find existing entry. - Profiler.BeginSample("(COF)[ObjectRepository] Get > Find existing entry"); - for (var i = 0; i < _cache.Count; ++i) - { - var entry = _cache[i]; - if (entry.hash != hash) continue; + if (GetFromCache(hash, ref obj)) return; + Add(hash, ref obj, onCreate(source)); + } + + private bool GetFromCache(Hash128 hash, ref T obj) + { + // Find existing entry. + Profiler.BeginSample("(COF)[ObjectRepository] GetFromCache"); + if (_cache.TryGetValue(hash, out var entry)) + { + if (!entry.storedObject) + { + Release(ref entry.storedObject); + Profiler.EndSample(); + return false; + } - // Existing entry found. if (entry.storedObject != obj) { // if the object is different, release the old one. Release(ref obj); ++entry.reference; obj = entry.storedObject; - Logging.Log(_name, $"Get(#{count}): {entry}"); + Logging.Log(_name, $"Get(total#{count}): {entry}"); } Profiler.EndSample(); - return; + return true; } Profiler.EndSample(); + return false; + } - // Create new entry. - Profiler.BeginSample("(COF)[ObjectRepository] Get > Create new entry"); + private void Add(Hash128 hash, ref T obj, T newObject) + { + if (!newObject) + { + Release(ref obj); + obj = newObject; + return; + } + + // Create and add a new entry. + Profiler.BeginSample("(COF)[ObjectRepository] Add"); var newEntry = 0 < _pool.Count ? _pool.Pop() : new Entry(); - newEntry.storedObject = onCreate(source); + newEntry.storedObject = newObject; newEntry.hash = hash; newEntry.reference = 1; - _cache.Add(newEntry); - Logging.Log(_name, $"Get(#{count}): {newEntry}"); - + _cache[hash] = newEntry; + _objectKey[newObject.GetInstanceID()] = hash; + Logging.Log(_name, $"Add(total#{count}): {newEntry}"); Release(ref obj); - obj = newEntry.storedObject; + obj = newObject; Profiler.EndSample(); } @@ -163,35 +144,45 @@ namespace Coffee.UIParticleInternal { if (ReferenceEquals(obj, null)) return; + // Find and release the entry. Profiler.BeginSample("(COF)[ObjectRepository] Release"); - for (var i = 0; i < _cache.Count; i++) + var id = obj.GetInstanceID(); + if (_objectKey.TryGetValue(id, out var hash) + && _cache.TryGetValue(hash, out var entry)) { - var entry = _cache[i]; - - if (entry.storedObject != obj) + entry.reference--; + if (entry.reference <= 0 || !entry.storedObject) { - continue; + Remove(entry); } - - if (--entry.reference <= 0) + else { - Profiler.BeginSample("(COF)[ObjectRepository] Release > RemoveAt"); - _cache.RemoveAtFast(i); - Logging.Log(_name, $"Release(#{_cache.Count}): {entry}"); - entry.Release(_onRelease); - _pool.Push(entry); - Profiler.EndSample(); - break; + Logging.Log(_name, $"Release(total#{_cache.Count}): {entry}"); } - - Logging.Log(_name, $"Release(#{count}): {entry}"); - break; + } + else + { + Logging.Log(_name, $"Release(total#{_cache.Count}): Already released: {obj}"); } obj = null; Profiler.EndSample(); } + private void Remove(Entry entry) + { + if (ReferenceEquals(entry, null)) return; + + Profiler.BeginSample("(COF)[ObjectRepository] Remove"); + _cache.Remove(entry.hash); + _objectKey.Remove(entry.storedObject.GetInstanceID()); + _pool.Push(entry); + entry.reference = 0; + Logging.Log(_name, $"Remove(total#{_cache.Count}): {entry}"); + entry.Release(_onRelease); + Profiler.EndSample(); + } + private class Entry { public Hash128 hash; @@ -211,7 +202,7 @@ namespace Coffee.UIParticleInternal public override string ToString() { - return $"h{(uint)hash.GetHashCode()} (#{reference}), {storedObject}"; + return $"h{(uint)hash.GetHashCode()} (refs#{reference}), {storedObject}"; } } }