initial commit
This commit is contained in:
parent
6715289efe
commit
788c3389af
37645 changed files with 2526849 additions and 80 deletions
|
@ -0,0 +1,135 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace UnityEngine.ResourceManagement.Diagnostics
|
||||
{
|
||||
/// <summary>
|
||||
/// Diagnostic event data.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct DiagnosticEvent
|
||||
{
|
||||
[SerializeField]
|
||||
string m_Graph; //id of graph definition to use
|
||||
|
||||
[SerializeField]
|
||||
int[] m_Dependencies; //used to nest datagraphs
|
||||
|
||||
[SerializeField]
|
||||
int m_ObjectId; //id of a set of data streams
|
||||
|
||||
[SerializeField]
|
||||
string m_DisplayName;
|
||||
|
||||
[SerializeField]
|
||||
int m_Stream; //data stream
|
||||
|
||||
[SerializeField]
|
||||
int m_Frame; //frame of the event
|
||||
|
||||
[SerializeField]
|
||||
int m_Value; //data value of event
|
||||
|
||||
/// <summary>
|
||||
/// Gets the graph id that this event is intended for
|
||||
/// </summary>
|
||||
/// <value>The graph Id</value>
|
||||
public string Graph
|
||||
{
|
||||
get { return m_Graph; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unique object identifier for this event
|
||||
/// </summary>
|
||||
public int ObjectId
|
||||
{
|
||||
get { return m_ObjectId; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Display name for event
|
||||
/// </summary>
|
||||
public string DisplayName
|
||||
{
|
||||
get { return m_DisplayName; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Array of object identifiers that are dependencies for this event
|
||||
/// </summary>
|
||||
public int[] Dependencies
|
||||
{
|
||||
get { return m_Dependencies; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The stream id for the event. Each graph may display multiple streams of data for the same event Id
|
||||
/// </summary>
|
||||
/// <value>Stream Id</value>
|
||||
public int Stream
|
||||
{
|
||||
get { return m_Stream; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The frame that the event occurred
|
||||
/// </summary>
|
||||
/// <value>Frame number</value>
|
||||
public int Frame
|
||||
{
|
||||
get { return m_Frame; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The value of the event. This value depends on the event type
|
||||
/// </summary>
|
||||
/// <value>Event value</value>
|
||||
public int Value
|
||||
{
|
||||
get { return m_Value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DiagnosticEvent constructor
|
||||
/// </summary>
|
||||
/// <param name="graph">Graph id.</param>
|
||||
/// <param name="name">Event name.</param>
|
||||
/// <param name="id">Event id.</param>
|
||||
/// <param name="stream">Stream index.</param>
|
||||
/// <param name="frame">Frame number.</param>
|
||||
/// <param name="value">Event value.</param>
|
||||
/// <param name="deps">Array of dependency event ids.</param>
|
||||
public DiagnosticEvent(string graph, string name, int id, int stream, int frame, int value, int[] deps)
|
||||
{
|
||||
m_Graph = graph;
|
||||
m_DisplayName = name;
|
||||
m_ObjectId = id;
|
||||
m_Stream = stream;
|
||||
m_Frame = frame;
|
||||
m_Value = value;
|
||||
m_Dependencies = deps;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the event into JSON and then encodes with System.Text.Encoding.ASCII.GetBytes
|
||||
/// </summary>
|
||||
/// <returns>Byte array containing serialized version of the event</returns>
|
||||
internal byte[] Serialize()
|
||||
{
|
||||
return Encoding.ASCII.GetBytes(JsonUtility.ToJson(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes event from a byte array created by the <see cref="Serialize"/> method
|
||||
/// </summary>
|
||||
/// <returns>Deserialized DiagnosticEvent struct</returns>
|
||||
/// <param name="data">Serialized data</param>
|
||||
public static DiagnosticEvent Deserialize(byte[] data)
|
||||
{
|
||||
return JsonUtility.FromJson<DiagnosticEvent>(Encoding.ASCII.GetString(data));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8262b6bbc428e3147b18b7f7f4527359
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,198 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
// ReSharper disable DelegateSubtraction
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.Networking.PlayerConnection;
|
||||
#endif
|
||||
|
||||
using UnityEngine.Networking.PlayerConnection;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
|
||||
namespace UnityEngine.ResourceManagement.Diagnostics
|
||||
{
|
||||
/// <summary>
|
||||
/// Collects ResourceManager events and passed them on the registered event handlers. In editor play mode, events are passed directly to the ResourceManager profiler window.
|
||||
/// In player builds, events are sent to the editor via the EditorConnection API.
|
||||
/// </summary>
|
||||
public class DiagnosticEventCollectorSingleton : ComponentSingleton<DiagnosticEventCollectorSingleton>
|
||||
{
|
||||
static Guid s_editorConnectionGuid;
|
||||
|
||||
internal Dictionary<int, DiagnosticEvent> m_CreatedEvents = new Dictionary<int, DiagnosticEvent>();
|
||||
internal List<DiagnosticEvent> m_UnhandledEvents = new List<DiagnosticEvent>();
|
||||
|
||||
internal DelegateList<DiagnosticEvent> s_EventHandlers = DelegateList<DiagnosticEvent>.CreateWithGlobalCache();
|
||||
|
||||
/// <summary>
|
||||
/// The guid used for the PlayerConnect messaging system.
|
||||
/// </summary>
|
||||
public static Guid PlayerConnectionGuid
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_editorConnectionGuid == Guid.Empty)
|
||||
s_editorConnectionGuid = new Guid(1, 2, 3, new byte[] {20, 1, 32, 32, 4, 9, 6, 44});
|
||||
return s_editorConnectionGuid;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string GetGameObjectName() => "EventCollector";
|
||||
|
||||
/// <summary>
|
||||
/// Register for diagnostic events. If there is no collector, this will fail and return false.
|
||||
/// </summary>
|
||||
/// <param name="handler">The handler method action.</param>
|
||||
/// <param name="register">Register or unregister.</param>
|
||||
/// <param name="create">If true, the event collector will be created if needed.</param>
|
||||
/// <returns>True if registered, false if not.</returns>
|
||||
public static bool RegisterEventHandler(Action<DiagnosticEvent> handler, bool register, bool create)
|
||||
{
|
||||
if (register && (create || Exists))
|
||||
{
|
||||
Instance.RegisterEventHandler(handler);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!register && Exists)
|
||||
{
|
||||
Instance.UnregisterEventHandler(handler);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal void RegisterEventHandler(Action<DiagnosticEvent> handler)
|
||||
{
|
||||
Debug.Assert(m_UnhandledEvents != null, "DiagnosticEventCollectorSingleton.RegisterEventHandler - s_unhandledEvents == null.");
|
||||
if (handler == null)
|
||||
throw new ArgumentNullException("handler");
|
||||
s_EventHandlers.Add(handler);
|
||||
|
||||
//Ensure that events are handled in frame order
|
||||
var combinedAndSortedList = m_UnhandledEvents.Concat(m_CreatedEvents.Values).OrderBy(evt => evt.Frame);
|
||||
foreach (var evt in combinedAndSortedList)
|
||||
handler(evt);
|
||||
m_UnhandledEvents.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unregister event hander
|
||||
/// </summary>
|
||||
/// <param name="handler">Method or delegate that will handle the events</param>
|
||||
public void UnregisterEventHandler(Action<DiagnosticEvent> handler)
|
||||
{
|
||||
if (handler == null)
|
||||
throw new ArgumentNullException("handler");
|
||||
s_EventHandlers.Remove(handler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a <see cref="DiagnosticEvent"/> event to all registered handlers
|
||||
/// </summary>
|
||||
/// <param name="diagnosticEvent">The event to send</param>
|
||||
public void PostEvent(DiagnosticEvent diagnosticEvent)
|
||||
{
|
||||
if (diagnosticEvent.Stream == (int)ResourceManager.DiagnosticEventType.AsyncOperationCreate && !m_CreatedEvents.ContainsKey(diagnosticEvent.ObjectId))
|
||||
m_CreatedEvents.Add(diagnosticEvent.ObjectId, diagnosticEvent);
|
||||
else if (diagnosticEvent.Stream == (int)ResourceManager.DiagnosticEventType.AsyncOperationDestroy)
|
||||
m_CreatedEvents.Remove(diagnosticEvent.ObjectId);
|
||||
|
||||
Debug.Assert(m_UnhandledEvents != null, "DiagnosticEventCollectorSingleton.PostEvent - s_unhandledEvents == null.");
|
||||
|
||||
if (s_EventHandlers.Count > 0)
|
||||
s_EventHandlers.Invoke(diagnosticEvent);
|
||||
else
|
||||
m_UnhandledEvents.Add(diagnosticEvent);
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
#if !UNITY_EDITOR
|
||||
RegisterEventHandler((DiagnosticEvent diagnosticEvent) => {PlayerConnection.instance.Send(DiagnosticEventCollectorSingleton.PlayerConnectionGuid, diagnosticEvent.Serialize()); });
|
||||
#endif
|
||||
}
|
||||
|
||||
float m_lastTickSent = 0;
|
||||
int m_lastFrame = 0;
|
||||
float fpsAvg = 30;
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (s_EventHandlers.Count > 0)
|
||||
{
|
||||
var elapsed = Time.realtimeSinceStartup - m_lastTickSent;
|
||||
if (elapsed > .25f)
|
||||
{
|
||||
var fps = (Time.frameCount - m_lastFrame) / elapsed;
|
||||
m_lastFrame = Time.frameCount;
|
||||
fpsAvg = (fpsAvg + fps) * .5f;
|
||||
m_lastTickSent = Time.realtimeSinceStartup;
|
||||
int heapKB = (int)(UnityEngine.Profiling.Profiler.GetMonoUsedSizeLong() / 1024);
|
||||
PostEvent(new DiagnosticEvent("FrameCount", "FPS", 2, 1, Time.frameCount, (int)fpsAvg, null));
|
||||
PostEvent(new DiagnosticEvent("MemoryCount", "MonoHeap", 3, 2, Time.frameCount, heapKB, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collects ResourceManager events and passed them on the registered event handlers. In editor play mode, events are passed directly to the ResourceManager profiler window.
|
||||
/// In player builds, events are sent to the editor via the EditorConnection API.
|
||||
/// </summary>
|
||||
public class DiagnosticEventCollector : MonoBehaviour
|
||||
{
|
||||
static DiagnosticEventCollector s_Collector;
|
||||
|
||||
/// <summary>
|
||||
/// The guid used for the PlayerConnect messaging system.
|
||||
/// </summary>
|
||||
public static Guid PlayerConnectionGuid => DiagnosticEventCollectorSingleton.PlayerConnectionGuid;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the global event collector. A new one is created if needed.
|
||||
/// </summary>
|
||||
/// <returns>The event collector global instance.</returns>
|
||||
public static DiagnosticEventCollector FindOrCreateGlobalInstance()
|
||||
{
|
||||
if (s_Collector == null)
|
||||
{
|
||||
var go = new GameObject("EventCollector", typeof(DiagnosticEventCollector));
|
||||
s_Collector = go.GetComponent<DiagnosticEventCollector>();
|
||||
go.hideFlags = HideFlags.DontSave; // HideFlags.HideAndDontSave;
|
||||
}
|
||||
|
||||
return s_Collector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register for diagnostic events. If there is no collector, this will fail and return false.
|
||||
/// </summary>
|
||||
/// <param name="handler">The handler method action.</param>
|
||||
/// <param name="register">Register or unregister.</param>
|
||||
/// <param name="create">If true, the event collector will be created if needed.</param>
|
||||
/// <returns>True if registered, false if not.</returns>
|
||||
public static bool RegisterEventHandler(Action<DiagnosticEvent> handler, bool register, bool create) => DiagnosticEventCollectorSingleton.RegisterEventHandler(handler, register, create);
|
||||
|
||||
/// <summary>
|
||||
/// Unregister event hander
|
||||
/// </summary>
|
||||
/// <param name="handler">Method or delegate that will handle the events</param>
|
||||
public void UnregisterEventHandler(Action<DiagnosticEvent> handler) => DiagnosticEventCollectorSingleton.Instance.UnregisterEventHandler(handler);
|
||||
|
||||
/// <summary>
|
||||
/// Send a <see cref="DiagnosticEvent"/> event to all registered handlers
|
||||
/// </summary>
|
||||
/// <param name="diagnosticEvent">The event to send</param>
|
||||
public void PostEvent(DiagnosticEvent diagnosticEvent) => DiagnosticEventCollectorSingleton.Instance.PostEvent(diagnosticEvent);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static class PlayStateNotifier
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 09b260528be79b74ab75d43b23001eab
|
||||
timeCreated: 1509377634
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e64db96403bd54244820848cd058a3be
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,87 @@
|
|||
#if ENABLE_ADDRESSABLE_PROFILER
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
|
||||
namespace UnityEngine.ResourceManagement.Profiling
|
||||
{
|
||||
[System.Flags]
|
||||
internal enum ContentStatus
|
||||
{
|
||||
None = 0,
|
||||
// 1
|
||||
Queue = 2,
|
||||
Downloading = 4,
|
||||
// 8
|
||||
Released = 16,
|
||||
// 32
|
||||
Loading = 64,
|
||||
// 128
|
||||
Active = 256,
|
||||
}
|
||||
|
||||
[System.Flags]
|
||||
internal enum BundleOptions : short
|
||||
{
|
||||
None = 0,
|
||||
CachingEnabled = 1,
|
||||
CheckSumEnabled = 2
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct CatalogFrameData
|
||||
{
|
||||
public Hash128 BuildResultHash;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct BundleFrameData
|
||||
{
|
||||
public int BundleCode;
|
||||
public int ReferenceCount;
|
||||
public float PercentComplete;
|
||||
public ContentStatus Status;
|
||||
public BundleSource Source;
|
||||
public BundleOptions LoadingOptions;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct AssetFrameData
|
||||
{
|
||||
public int AssetCode;
|
||||
public int BundleCode;
|
||||
public int ReferenceCount;
|
||||
public float PercentComplete;
|
||||
public ContentStatus Status;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (obj is AssetFrameData other)
|
||||
{
|
||||
return AssetCode == other.AssetCode &&
|
||||
BundleCode == other.BundleCode;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
#if UNITY_2022_2_OR_NEWER
|
||||
return HashCode.Combine(AssetCode.GetHashCode(), BundleCode.GetHashCode(), ReferenceCount.GetHashCode(), PercentComplete.GetHashCode(), Status.GetHashCode());
|
||||
#else
|
||||
int hash = 17;
|
||||
hash = hash * 31 + AssetCode.GetHashCode();
|
||||
hash = hash * 31 + BundleCode.GetHashCode();
|
||||
hash = hash * 31 + ReferenceCount.GetHashCode();
|
||||
hash = hash * 31 + PercentComplete.GetHashCode();
|
||||
hash = hash * 31 + Status.GetHashCode();
|
||||
return hash;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6b781cca3dbc4b12bd34a2f36633abca
|
||||
timeCreated: 1665140928
|
|
@ -0,0 +1,90 @@
|
|||
#if ENABLE_ADDRESSABLE_PROFILER
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.ResourceManagement.Profiling
|
||||
{
|
||||
internal class ProfilerFrameData<T1,T2>
|
||||
{
|
||||
private Dictionary<T1, T2> m_Data = new Dictionary<T1, T2>();
|
||||
|
||||
private T2[] m_Array;
|
||||
private uint m_Version;
|
||||
private uint m_ArrayVersion;
|
||||
|
||||
public bool Add(T1 key, T2 value)
|
||||
{
|
||||
bool alreadyExist = m_Data.ContainsKey(key);
|
||||
m_Data[key] = value;
|
||||
m_Version++;
|
||||
return !alreadyExist;
|
||||
}
|
||||
|
||||
internal bool Remove(T1 key)
|
||||
{
|
||||
bool removed = m_Data.Remove(key);
|
||||
if (removed)
|
||||
m_Version++;
|
||||
return removed;
|
||||
}
|
||||
|
||||
public T2[] Values
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_ArrayVersion == m_Version)
|
||||
return m_Array ?? Array.Empty<T2>();
|
||||
m_Array = new T2[m_Data.Count];
|
||||
m_Data.Values.CopyTo(m_Array, 0);
|
||||
m_ArrayVersion = m_Version;
|
||||
return m_Array;
|
||||
}
|
||||
}
|
||||
|
||||
public T2 this[T1 key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!m_Data.TryGetValue(key, out T2 value))
|
||||
throw new System.ArgumentOutOfRangeException($"Key {key.ToString()} not found for FrameData");
|
||||
return value;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (m_Array != null && m_Data.TryGetValue(key, out T2 oldValue))
|
||||
{
|
||||
for (int i = 0; i < m_Array.Length; ++i)
|
||||
{
|
||||
if (m_Array[i].Equals(oldValue))
|
||||
{
|
||||
m_Array[i] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_Data[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetValue(T1 key, out T2 value)
|
||||
{
|
||||
return m_Data.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
public bool ContainsKey(T1 key)
|
||||
{
|
||||
return m_Data.ContainsKey(key);
|
||||
}
|
||||
|
||||
public IEnumerable<KeyValuePair<T1,T2>> Enumerate()
|
||||
{
|
||||
foreach (var pair in m_Data)
|
||||
{
|
||||
yield return pair;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6a881c35c9c8410fa42113c516121903
|
||||
timeCreated: 1664977838
|
|
@ -0,0 +1,290 @@
|
|||
#if ENABLE_ADDRESSABLE_PROFILER
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Unity.Profiling;
|
||||
using UnityEngine.Profiling;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceLocations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.ResourceManagement.Util;
|
||||
|
||||
namespace UnityEngine.ResourceManagement.Profiling
|
||||
{
|
||||
internal static class ProfilerRuntime
|
||||
{
|
||||
public static readonly Guid kResourceManagerProfilerGuid = new Guid("4f8a8c93-7634-4ef7-bbbc-6c9928567fa4");
|
||||
public const int kCatalogTag = 0;
|
||||
public const int kBundleDataTag = 1;
|
||||
public const int kAssetDataTag = 2;
|
||||
public const int kSceneDataTag = 3;
|
||||
|
||||
private static ProfilerCounterValue<int> CatalogLoadCounter = new ProfilerCounterValue<int>(ProfilerCategory.Loading, "Catalogs", ProfilerMarkerDataUnit.Count);
|
||||
private static ProfilerCounterValue<int> AssetBundleLoadCounter = new ProfilerCounterValue<int>(ProfilerCategory.Loading, "Asset Bundles", ProfilerMarkerDataUnit.Count);
|
||||
private static ProfilerCounterValue<int> AssetLoadCounter = new ProfilerCounterValue<int>(ProfilerCategory.Loading, "Assets", ProfilerMarkerDataUnit.Count);
|
||||
private static ProfilerCounterValue<int> SceneLoadCounter = new ProfilerCounterValue<int>(ProfilerCategory.Loading, "Scenes", ProfilerMarkerDataUnit.Count);
|
||||
|
||||
private static ProfilerFrameData<Hash128, CatalogFrameData> m_CatalogData = new ProfilerFrameData<Hash128, CatalogFrameData>();
|
||||
private static ProfilerFrameData<IAsyncOperation, BundleFrameData> m_BundleData = new ProfilerFrameData<IAsyncOperation, BundleFrameData>();
|
||||
private static ProfilerFrameData<IAsyncOperation, AssetFrameData> m_AssetData = new ProfilerFrameData<IAsyncOperation, AssetFrameData>();
|
||||
private static ProfilerFrameData<IAsyncOperation, AssetFrameData> m_SceneData = new ProfilerFrameData<IAsyncOperation, AssetFrameData>();
|
||||
|
||||
private static Dictionary<string, IAsyncOperation> m_BundleNameToOperation = new Dictionary<string, IAsyncOperation>();
|
||||
private static Dictionary<string, List<IAsyncOperation>> m_BundleNameToAssetOperations = new Dictionary<string, List<IAsyncOperation>>();
|
||||
|
||||
public static void Initialise()
|
||||
{
|
||||
CatalogLoadCounter.Value = 0;
|
||||
AssetBundleLoadCounter.Value = 0;
|
||||
AssetLoadCounter.Value = 0;
|
||||
SceneLoadCounter.Value = 0;
|
||||
|
||||
MonoBehaviourCallbackHooks.Instance.OnLateUpdateDelegate += InstanceOnOnLateUpdateDelegate;
|
||||
}
|
||||
|
||||
private static void InstanceOnOnLateUpdateDelegate(float deltaTime)
|
||||
{
|
||||
PushToProfilerStream();
|
||||
}
|
||||
|
||||
public static void AddCatalog(Hash128 buildHash)
|
||||
{
|
||||
if (!buildHash.isValid)
|
||||
return;
|
||||
|
||||
m_CatalogData.Add(buildHash, new CatalogFrameData(){BuildResultHash = buildHash});
|
||||
CatalogLoadCounter.Value++;
|
||||
}
|
||||
|
||||
public static void AddBundleOperation(ProvideHandle handle, [NotNull] AssetBundleRequestOptions requestOptions, ContentStatus status, BundleSource source)
|
||||
{
|
||||
IAsyncOperation op = handle.InternalOp as IAsyncOperation;
|
||||
if (op == null)
|
||||
{
|
||||
string msg = "Could not get Bundle operation for handle loaded for Key " + handle.Location.PrimaryKey;
|
||||
throw new System.NullReferenceException(msg);
|
||||
}
|
||||
|
||||
string bundleName = requestOptions.BundleName;
|
||||
BundleOptions loadingOptions = BundleOptions.None;
|
||||
|
||||
bool doCRC = requestOptions.Crc != 0;
|
||||
if (doCRC && source == BundleSource.Cache)
|
||||
doCRC = requestOptions.UseCrcForCachedBundle;
|
||||
if (doCRC)
|
||||
loadingOptions |= BundleOptions.CheckSumEnabled;
|
||||
if (!string.IsNullOrEmpty(requestOptions.Hash))
|
||||
loadingOptions |= BundleOptions.CachingEnabled;
|
||||
|
||||
BundleFrameData data = new BundleFrameData()
|
||||
{
|
||||
ReferenceCount = op.ReferenceCount,
|
||||
BundleCode = bundleName.GetHashCode(),
|
||||
Status = status,
|
||||
LoadingOptions = loadingOptions,
|
||||
Source = source
|
||||
};
|
||||
|
||||
m_BundleData.Add(op, data);
|
||||
if (!m_BundleNameToOperation.ContainsKey(bundleName))
|
||||
AssetBundleLoadCounter.Value += 1;
|
||||
m_BundleNameToOperation[bundleName] = op;
|
||||
}
|
||||
|
||||
public static void BundleReleased(string bundleName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(bundleName) || !m_BundleNameToOperation.TryGetValue(bundleName, out var op))
|
||||
return;
|
||||
|
||||
m_BundleData.Remove(op);
|
||||
m_BundleNameToOperation.Remove(bundleName);
|
||||
AssetBundleLoadCounter.Value -= 1;
|
||||
|
||||
// remove all the assets from the bundle
|
||||
if (m_BundleNameToAssetOperations.TryGetValue(bundleName, out var assetOps))
|
||||
{
|
||||
m_BundleNameToAssetOperations.Remove(bundleName);
|
||||
foreach (IAsyncOperation assetOp in assetOps)
|
||||
{
|
||||
AssetLoadCounter.Value -= 1;
|
||||
m_AssetData.Remove(assetOp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddAssetOperation(ProvideHandle handle, ContentStatus status)
|
||||
{
|
||||
if (!handle.IsValid)
|
||||
throw new ArgumentException("Attempting to add a Asset handle to profiler that is not valid");
|
||||
IAsyncOperation assetLoadOperation = handle.InternalOp as IAsyncOperation;
|
||||
if (assetLoadOperation == null)
|
||||
throw new NullReferenceException("Could not get operation for InternalOp of handle loaded with primary key: " + handle.Location.PrimaryKey);
|
||||
|
||||
string containingBundleName = GetContainingBundleNameForLocation(handle.Location);
|
||||
|
||||
string assetId;
|
||||
if (handle.Location.InternalId.EndsWith(']'))
|
||||
{
|
||||
int start = handle.Location.InternalId.IndexOf('[');
|
||||
assetId = handle.Location.InternalId.Remove(start);
|
||||
}
|
||||
else
|
||||
assetId = handle.Location.InternalId;
|
||||
|
||||
AssetFrameData profileObject = new AssetFrameData();
|
||||
profileObject.AssetCode = assetId.GetHashCode();
|
||||
profileObject.ReferenceCount = assetLoadOperation.ReferenceCount;
|
||||
profileObject.BundleCode = containingBundleName.GetHashCode();
|
||||
profileObject.Status = status;
|
||||
|
||||
if (m_BundleNameToAssetOperations.TryGetValue(containingBundleName, out List<IAsyncOperation> assetOperations))
|
||||
{
|
||||
if (!assetOperations.Contains(assetLoadOperation))
|
||||
assetOperations.Add(assetLoadOperation);
|
||||
}
|
||||
else
|
||||
m_BundleNameToAssetOperations.Add(containingBundleName, new List<IAsyncOperation>(){assetLoadOperation});
|
||||
|
||||
if (m_AssetData.Add(assetLoadOperation, profileObject))
|
||||
AssetLoadCounter.Value += 1;
|
||||
}
|
||||
|
||||
private static string GetContainingBundleNameForLocation(IResourceLocation location)
|
||||
{
|
||||
if (location.Dependencies.Count == 0)
|
||||
{
|
||||
// AssetDatabase mode has no dependencies
|
||||
return "";
|
||||
}
|
||||
|
||||
AssetBundleRequestOptions options = location.Dependencies[0].Data as AssetBundleRequestOptions;
|
||||
if (options == null)
|
||||
{
|
||||
Debug.LogError($"Dependency bundle location does not have AssetBundleRequestOptions");
|
||||
return "";
|
||||
}
|
||||
|
||||
return options.BundleName;
|
||||
}
|
||||
|
||||
public static void AddSceneOperation(AsyncOperationHandle<SceneInstance> handle, IResourceLocation location, ContentStatus status)
|
||||
{
|
||||
IAsyncOperation sceneLoadOperation = handle.InternalOp as IAsyncOperation;
|
||||
Debug.Assert(sceneLoadOperation != null, "Could not get operation for " + location.PrimaryKey);
|
||||
|
||||
string containingBundleName = GetContainingBundleNameForLocation(location);
|
||||
|
||||
AssetFrameData profileObject = new AssetFrameData();
|
||||
profileObject.AssetCode = location.InternalId.GetHashCode();
|
||||
profileObject.ReferenceCount = sceneLoadOperation.ReferenceCount;
|
||||
profileObject.BundleCode = containingBundleName.GetHashCode();
|
||||
profileObject.Status = status;
|
||||
|
||||
if (m_SceneData.Add(sceneLoadOperation, profileObject))
|
||||
SceneLoadCounter.Value += 1;
|
||||
}
|
||||
|
||||
public static void SceneReleased(AsyncOperationHandle<SceneInstance> handle)
|
||||
{
|
||||
if (handle.InternalOp is ChainOperationTypelessDepedency<SceneInstance> chainOp)
|
||||
{
|
||||
if (m_SceneData.Remove(chainOp.WrappedOp.InternalOp))
|
||||
SceneLoadCounter.Value -= 1;
|
||||
else
|
||||
Debug.LogWarning($"Failed to remove scene from Addressables profiler for " + chainOp.WrappedOp.DebugName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_SceneData.Remove(handle.InternalOp))
|
||||
SceneLoadCounter.Value -= 1;
|
||||
else
|
||||
Debug.LogWarning($"Failed to remove scene from Addressables profiler for " + handle.DebugName);
|
||||
}
|
||||
}
|
||||
|
||||
private static void PushToProfilerStream()
|
||||
{
|
||||
RefreshChangedReferenceCounts();
|
||||
Profiler.EmitFrameMetaData(kResourceManagerProfilerGuid, kCatalogTag, m_CatalogData.Values);
|
||||
Profiler.EmitFrameMetaData(kResourceManagerProfilerGuid, kBundleDataTag, m_BundleData.Values);
|
||||
Profiler.EmitFrameMetaData(kResourceManagerProfilerGuid, kAssetDataTag, m_AssetData.Values);
|
||||
Profiler.EmitFrameMetaData(kResourceManagerProfilerGuid, kSceneDataTag, m_SceneData.Values);
|
||||
}
|
||||
|
||||
private static void RefreshChangedReferenceCounts()
|
||||
{
|
||||
Dictionary<IAsyncOperation, (int, float)> dataToChange = new Dictionary<IAsyncOperation, (int, float)>();
|
||||
|
||||
foreach (KeyValuePair<IAsyncOperation, BundleFrameData> pair in m_BundleData.Enumerate())
|
||||
{
|
||||
if (ShouldUpdateFrameDataWithOperationData(pair.Key, pair.Value.ReferenceCount, pair.Value.PercentComplete, out (int, float) newValues))
|
||||
dataToChange.Add(pair.Key, newValues);
|
||||
}
|
||||
foreach (KeyValuePair<IAsyncOperation, (int, float)> pair in dataToChange)
|
||||
{
|
||||
var temp = m_BundleData[pair.Key];
|
||||
temp.ReferenceCount = pair.Value.Item1;
|
||||
temp.PercentComplete = pair.Value.Item2;
|
||||
m_BundleData[pair.Key] = temp;
|
||||
}
|
||||
dataToChange.Clear();
|
||||
|
||||
foreach (KeyValuePair<IAsyncOperation,AssetFrameData> pair in m_AssetData.Enumerate())
|
||||
{
|
||||
if (ShouldUpdateFrameDataWithOperationData(pair.Key, pair.Value.ReferenceCount, pair.Value.PercentComplete, out (int, float) newValues))
|
||||
dataToChange.Add(pair.Key, newValues);
|
||||
}
|
||||
foreach (KeyValuePair<IAsyncOperation, (int, float)> pair in dataToChange)
|
||||
{
|
||||
var temp = m_AssetData[pair.Key];
|
||||
temp.ReferenceCount = pair.Value.Item1;
|
||||
temp.PercentComplete = pair.Value.Item2;
|
||||
m_AssetData[pair.Key] = temp;
|
||||
}
|
||||
dataToChange.Clear();
|
||||
|
||||
foreach (KeyValuePair<IAsyncOperation,AssetFrameData> pair in m_SceneData.Enumerate())
|
||||
{
|
||||
if (ShouldUpdateFrameDataWithOperationData(pair.Key, pair.Value.ReferenceCount, pair.Value.PercentComplete, out (int, float) newValues))
|
||||
dataToChange.Add(pair.Key, newValues);
|
||||
}
|
||||
foreach (KeyValuePair<IAsyncOperation, (int, float)> pair in dataToChange)
|
||||
{
|
||||
var temp = m_SceneData[pair.Key];
|
||||
temp.ReferenceCount = pair.Value.Item1;
|
||||
temp.PercentComplete = pair.Value.Item2;
|
||||
m_SceneData[pair.Key] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
// Because the ProfilerFrameData keeps track of both a dictionary and array, and not updated often,
|
||||
// check if done on if to update the collection
|
||||
private static bool ShouldUpdateFrameDataWithOperationData(IAsyncOperation activeOperation, int frameReferenceCount, float framePercentComplete, out (int, float) newDataOut)
|
||||
{
|
||||
int currentReferenceCount = activeOperation.ReferenceCount;
|
||||
switch (activeOperation.Status)
|
||||
{
|
||||
case AsyncOperationStatus.Succeeded:
|
||||
break;
|
||||
case AsyncOperationStatus.Failed:
|
||||
currentReferenceCount = 0;
|
||||
break;
|
||||
case AsyncOperationStatus.None:
|
||||
bool inProgress = !activeOperation.IsDone && activeOperation.IsRunning;
|
||||
if (!inProgress)
|
||||
currentReferenceCount = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
float currentPercentComplete = activeOperation.PercentComplete;
|
||||
|
||||
newDataOut = (currentReferenceCount, currentPercentComplete);
|
||||
|
||||
return currentReferenceCount != frameReferenceCount
|
||||
|| !Mathf.Approximately(currentPercentComplete, framePercentComplete);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fe634a3decf6743b4918c03e2ae2642c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue