static void ApplySpikeOverlay(SpikeWindowInfo info, Color spikeColor) { var spikeOverlayParent = info.spikeOverlayParent; if (info.isInspectorElement) { if (info.spikeOverlay == null) { info.spikeOverlay = CreateSpikeOverlay(); info.spikeOverlay.name = info.trackerName; spikeOverlayParent.Add(info.spikeOverlay); } var color = spikeColor; color.a = 0.05f; info.spikeOverlay.style.backgroundColor = color; } else { if (spikeOverlayParent == null) { return; } if (info.spikeOverlay == null) { info.spikeOverlay = CreateSpikeOverlay(); spikeOverlayParent.Add(info.spikeOverlay); } else { // Check if it is still the last element: var childCount = spikeOverlayParent.childCount; if (childCount > 0 && spikeOverlayParent.ElementAt(childCount - 1) == info.spikeOverlay) { // All is good, perf Overlay is the last item. Nothing to do. } else { // Ensure it is last: if (spikeOverlayParent.Contains(info.spikeOverlay)) { spikeOverlayParent.Remove(info.spikeOverlay); } spikeOverlayParent.Add(info.spikeOverlay); } } WindowBorderState.ApplyToStyle(info.spikeOverlay, spikeColor); } info.paintTriggeredByStateChanged = true; if (PerformanceTrackerSettings.spikeHighlightStrategy == SpikeHighlightStrategy.AvgTime) { EditorPerformanceTracker.Reset(info.trackerName); } }
static void PerformSpikeWindowHighlight(double now, string[] trackerNames) { if (!PerformanceTrackerSettings.spikeHighlightEnabled) { return; } var allEditorWindows = Resources.FindObjectsOfTypeAll <EditorWindow>(); foreach (var window in allEditorWindows) { var windowMarker = GetWindowPaintMarker(window); if (EditorPerformanceTracker.Exists(windowMarker)) { if (!s_SpikeWindowInfos.TryGetValue(windowMarker, out var spikeInfo)) { spikeInfo = new SpikeWindowInfo(window, windowMarker); s_SpikeWindowInfos.Add(windowMarker, spikeInfo); } UpdateSpikeWindow(now, spikeInfo); if (spikeInfo.isInspectorWindow && PerformanceTrackerSettings.inspectorSpikeHighlightEnabled) { using (new PerformanceTracker("Tracker.UpdateInspectors")) { UpdateInspectors(now, spikeInfo); } } } else if (s_SpikeWindowInfos.TryGetValue(windowMarker, out var spikeInfo)) { RemoveSpikeOverlay(spikeInfo); } } // Window is hidden or closed: clean up all spikeOverlay var infos = s_SpikeWindowInfos.Values.ToArray(); foreach (var info in infos) { if (!info.window) { RemoveSpikeOverlay(info); } } }
static void UpdateInspectors(double now, SpikeWindowInfo inspectorInfo) { var editorsList = inspectorInfo.window.rootVisualElement.Q(null, "unity-inspector-editors-list"); if (editorsList != null) { foreach (var editorElement in editorsList.Children()) { var name = editorElement.name; var markerName = $"Editor.{name}.OnInspectorGUI"; s_InspectorWindowInfos.TryGetValue(markerName, out var componentInfo); if (!EditorPerformanceTracker.Exists(markerName)) { if (componentInfo != null) { componentInfo.inUse = false; } continue; } if (componentInfo == null) { componentInfo = new SpikeWindowInfo(inspectorInfo.window, markerName, true, editorElement); s_InspectorWindowInfos.Add(markerName, componentInfo); } else if (editorElement != componentInfo.spikeOverlayParent) { InvalidateParent(componentInfo, editorElement); } componentInfo.inUse = true; UpdateSpikeWindow(now, componentInfo); } } var inspectorInfos = s_InspectorWindowInfos.Values.ToArray(); foreach (var info in inspectorInfos) { if (!info.inUse) { RemoveSpikeOverlay(info); } } }
static void RemoveSpikeOverlay(SpikeWindowInfo info) { ResetSpikeOverlay(info); if (info.isInspectorElement) { s_InspectorWindowInfos.Remove(info.trackerName); } else { s_SpikeWindowInfos.Remove(info.trackerName); if (info.isInspectorWindow) { var inspectorInfos = s_InspectorWindowInfos.Values.ToArray(); foreach (var inspectorInfo in inspectorInfos) { RemoveSpikeOverlay(inspectorInfo); } } } }
static void ResetSpikeOverlay(SpikeWindowInfo info, bool ignoreNextEvent = true) { info.spikeOverlay?.RemoveFromHierarchy(); info.spikeOverlay = null; info.lastSpikeTime = 0; info.lastTime = 0; if (ignoreNextEvent) { info.paintTriggeredByStateChanged = true; } if (info.window) { info.window.Repaint(); } if (PerformanceTrackerSettings.spikeHighlightStrategy == SpikeHighlightStrategy.AvgTime) { EditorPerformanceTracker.Reset(info.trackerName); } }
static void InvalidateParent(SpikeWindowInfo info, VisualElement parent = null) { info.spikeOverlayExplicitParent = parent; // We will be processing the event so do not prevent it. ResetSpikeOverlay(info, false); }
static void UpdateSpikeWindow(double now, SpikeWindowInfo info) { var avgTime = EditorPerformanceTracker.GetAverageTime(info.trackerName); var trackerLastTime = EditorPerformanceTracker.GetLastTime(info.trackerName); var sampleCount = EditorPerformanceTracker.GetSampleCount(info.trackerName); var peakTime = EditorPerformanceTracker.GetPeakTime(info.trackerName); var spikeDuration = info.lastSpikeTime == 0 ? 0 : now - info.lastSpikeTime; var currentTime = PerformanceTrackerSettings.spikeHighlightStrategy == SpikeHighlightStrategy.LastTime ? trackerLastTime : avgTime; var infoLastTime = PerformanceTrackerSettings.spikeHighlightStrategy == SpikeHighlightStrategy.LastTime ? info.lastTime : info.lastAvgTime; if (info.isSpiking && info.spikeOverlay.parent != info.spikeOverlayParent) { // Spike Overlay is not attached to the right window: probably a window that got docked or undocked. InvalidateParent(info); } if (!info.isSpiking && sampleCount == info.lastSampleCount) { // Nothing to do } else if (info.isSpiking && sampleCount == info.lastSampleCount) { // Check if needs to fade out if (spikeDuration > PerformanceTrackerSettings.spikeDuration) { ResetSpikeOverlay(info); } // Do not fade if we are already long to redraw else if (currentTime < PerformanceTrackerSettings.spikeCriticalThreshold && info.supportsFading) { // Try to fade out gently: var alphaFading = (float)((PerformanceTrackerSettings.spikeDuration - spikeDuration) / PerformanceTrackerSettings.spikeDuration); var color = info.spikeOverlay.style.borderBottomColor.value; color.a = alphaFading; ApplySpikeOverlay(info, color); } } else { // We just had an update of sample count: if (info.paintTriggeredByStateChanged) { // Discard this Paint event since it was caused by one of our state change info.paintTriggeredByStateChanged = false; } else if (currentTime > PerformanceTrackerSettings.spikeCriticalThreshold) { if (!info.isSpiking) { ApplySpikeOverlay(info, ComputeSpikeColor((float)currentTime, PerformanceTrackerSettings.spikeCriticalThreshold, 10.0f, PtStyles.criticalColor, Color.black)); } info.lastSpikeTime = now; } else if (currentTime > PerformanceTrackerSettings.spikeWarningThreshold) { if (!info.isSpiking) { ApplySpikeOverlay(info, ComputeSpikeColor((float)currentTime, PerformanceTrackerSettings.spikeWarningThreshold, PerformanceTrackerSettings.spikeCriticalThreshold, PtStyles.warningColor, PtStyles.criticalColor)); } info.lastSpikeTime = now; } else if (infoLastTime > PerformanceTrackerSettings.spikeWarningThreshold) { ResetSpikeOverlay(info); } } info.lastAvgTime = avgTime; info.lastTime = trackerLastTime; info.lastSampleCount = sampleCount; info.lastPeakTime = peakTime; }