// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Runtime.CompilerServices; using Unity.Profiling; using UnityEngine; using UnityEngine.EventSystems; [assembly: InternalsVisibleTo("Microsoft.MixedReality.Toolkit.Tests.PlayModeTests")] namespace Microsoft.MixedReality.Toolkit.Diagnostics { /// /// The default implementation of the /// [HelpURL("https://docs.microsoft.com/windows/mixed-reality/mrtk-unity/features/diagnostics/diagnostics-system-getting-started")] public class MixedRealityDiagnosticsSystem : BaseCoreSystem, IMixedRealityDiagnosticsSystem { /// /// Constructor. /// /// The instance that loaded the service. /// The configuration profile for the service. [System.Obsolete("This constructor is obsolete (registrar parameter is no longer required) and will be removed in a future version of the Microsoft Mixed Reality Toolkit.")] public MixedRealityDiagnosticsSystem( IMixedRealityServiceRegistrar registrar, MixedRealityDiagnosticsProfile profile) : this(profile) { Registrar = registrar; } /// /// Constructor. /// /// The configuration profile for the service. public MixedRealityDiagnosticsSystem( MixedRealityDiagnosticsProfile profile) : base(profile) { } /// public override string Name { get; protected set; } = "Mixed Reality Diagnostics System"; /// /// The parent object under which all visualization game objects will be placed. /// private GameObject diagnosticVisualizationParent = null; /// /// Creates the diagnostic visualizations and parents them so that the scene hierarchy does not get overly cluttered. /// private void CreateVisualizations() { diagnosticVisualizationParent = new GameObject("Diagnostics"); diagnosticVisualizationParent.AddComponent(); MixedRealityPlayspace.AddChild(diagnosticVisualizationParent.transform); diagnosticVisualizationParent.SetActive(ShowDiagnostics); // visual profiler settings visualProfiler = diagnosticVisualizationParent.AddComponent(); visualProfiler.WindowParent = diagnosticVisualizationParent.transform; visualProfiler.IsVisible = ShowProfiler; visualProfiler.FrameInfoVisible = ShowFrameInfo; visualProfiler.MemoryStatsVisible = ShowMemoryStats; visualProfiler.FrameSampleRate = FrameSampleRate; visualProfiler.WindowAnchor = WindowAnchor; visualProfiler.WindowOffset = WindowOffset; visualProfiler.WindowScale = WindowScale; visualProfiler.WindowFollowSpeed = WindowFollowSpeed; visualProfiler.ShowProfilerDuringMRC = ShowProfilerDuringMRC; } private MixedRealityToolkitVisualProfiler visualProfiler = null; #region IMixedRealityService /// public override void Initialize() { if (!Application.isPlaying) { return; } MixedRealityDiagnosticsProfile profile = ConfigurationProfile as MixedRealityDiagnosticsProfile; if (profile == null) { return; } base.Initialize(); eventData = new DiagnosticsEventData(EventSystem.current); // Apply profile settings ShowDiagnostics = profile.ShowDiagnostics; ShowProfiler = profile.ShowProfiler; ShowFrameInfo = profile.ShowFrameInfo; ShowMemoryStats = profile.ShowMemoryStats; FrameSampleRate = profile.FrameSampleRate; WindowAnchor = profile.WindowAnchor; WindowOffset = profile.WindowOffset; WindowScale = profile.WindowScale; WindowFollowSpeed = profile.WindowFollowSpeed; ShowProfilerDuringMRC = profile.ShowProfilerDuringMRC; CreateVisualizations(); } /// public override void Destroy() { if (diagnosticVisualizationParent != null) { if (Application.isEditor) { Object.DestroyImmediate(diagnosticVisualizationParent); } else { diagnosticVisualizationParent.transform.DetachChildren(); Object.Destroy(diagnosticVisualizationParent); } diagnosticVisualizationParent = null; } base.Destroy(); } #endregion IMixedRealityService #region IMixedRealityDiagnosticsSystem private MixedRealityDiagnosticsProfile diagnosticsSystemProfile = null; /// public MixedRealityDiagnosticsProfile DiagnosticsSystemProfile { get { if (diagnosticsSystemProfile == null) { diagnosticsSystemProfile = ConfigurationProfile as MixedRealityDiagnosticsProfile; } return diagnosticsSystemProfile; } } private bool showDiagnostics; /// public bool ShowDiagnostics { get { return showDiagnostics; } set { if (value != showDiagnostics) { showDiagnostics = value; // The voice commands are handled by the diagnosticVisualizationParent GameObject, we cannot disable the parent // or we lose the ability to re-show the visualizations. Instead, disable each visualization as appropriate. if (ShowProfiler) { visualProfiler.IsVisible = value; } } } } private bool showProfiler; /// public bool ShowProfiler { get { return showProfiler; } set { if (value != showProfiler) { showProfiler = value; if ((visualProfiler != null) && ShowDiagnostics) { visualProfiler.IsVisible = value; } } } } private bool showFrameInfo; /// public bool ShowFrameInfo { get { return showFrameInfo; } set { if (value != showFrameInfo) { showFrameInfo = value; if (visualProfiler != null) { visualProfiler.FrameInfoVisible = value; } } } } private bool showMemoryStats; /// public bool ShowMemoryStats { get { return showMemoryStats; } set { if (value != showMemoryStats) { showMemoryStats = value; if (visualProfiler != null) { visualProfiler.MemoryStatsVisible = value; } } } } private float frameSampleRate = 0.1f; /// public float FrameSampleRate { get { return frameSampleRate; } set { if (!Mathf.Approximately(frameSampleRate, value)) { frameSampleRate = value; if (visualProfiler != null) { visualProfiler.FrameSampleRate = frameSampleRate; } } } } #endregion IMixedRealityDiagnosticsSystem #region IMixedRealityEventSource private DiagnosticsEventData eventData; /// public uint SourceId => (uint)SourceName.GetHashCode(); /// public string SourceName => "Mixed Reality Diagnostics System"; /// public new bool Equals(object x, object y) => false; /// public int GetHashCode(object obj) => SourceName.GetHashCode(); internal void RaiseDiagnosticsChanged() { eventData.Initialize(this); HandleEvent(eventData, OnDiagnosticsChanged); } private static readonly ProfilerMarker OnDiagnosticsChangedPerfMarker = new ProfilerMarker("[MRTK] MixedRealityDiagnosticsSystem.OnDiagnosticsChanged - Raise event"); /// /// Event sent whenever the diagnostics visualization changes. /// private static readonly ExecuteEvents.EventFunction OnDiagnosticsChanged = delegate (IMixedRealityDiagnosticsHandler handler, BaseEventData eventData) { using (OnDiagnosticsChangedPerfMarker.Auto()) { var diagnosticsEventsData = ExecuteEvents.ValidateEventData(eventData); handler.OnDiagnosticSettingsChanged(diagnosticsEventsData); } }; #endregion IMixedRealityEventSource private TextAnchor windowAnchor = TextAnchor.LowerCenter; /// /// What part of the view port to anchor the window to. /// public TextAnchor WindowAnchor { get { return windowAnchor; } set { if (value != windowAnchor) { windowAnchor = value; if (visualProfiler != null) { visualProfiler.WindowAnchor = windowAnchor; } } } } private Vector2 windowOffset = new Vector2(0.1f, 0.1f); /// /// The offset from the view port center applied based on the window anchor selection. /// public Vector2 WindowOffset { get { return windowOffset; } set { if (value != windowOffset) { windowOffset = value; if (visualProfiler != null) { visualProfiler.WindowOffset = windowOffset; } } } } private float windowScale = 1.0f; /// /// Use to scale the window size up or down, can simulate a zooming effect. /// public float WindowScale { get { return windowScale; } set { if (value != windowScale) { windowScale = value; if (visualProfiler != null) { visualProfiler.WindowScale = windowScale; } } } } private float windowFollowSpeed = 5.0f; /// /// How quickly to interpolate the window towards its target position and rotation. /// public float WindowFollowSpeed { get { return windowFollowSpeed; } set { if (value != windowFollowSpeed) { windowFollowSpeed = value; if (visualProfiler != null) { visualProfiler.WindowFollowSpeed = windowFollowSpeed; } } } } private bool showProfilerDuringMRC = false; /// /// If the diagnostics profiler should be visible while a mixed reality capture is happening on HoloLens. /// /// This is not usually recommended, as MRC can have an effect on an app's frame rate. public bool ShowProfilerDuringMRC { get { return showProfilerDuringMRC; } set { if (value != showProfilerDuringMRC) { showProfilerDuringMRC = value; if (visualProfiler != null) { visualProfiler.ShowProfilerDuringMRC = showProfilerDuringMRC; } } } } } }