test
This commit is contained in:
@@ -0,0 +1,373 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Analytics;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Analytics;
|
||||
|
||||
namespace UnityEditor.Performance.ProfileAnalyzer
|
||||
{
|
||||
class ProfileAnalyzerAnalytics
|
||||
{
|
||||
const int k_MaxEventsPerHour = 100;
|
||||
const int k_MaxEventItems = 1000;
|
||||
const string k_VendorKey = "unity.profileanalyzer";
|
||||
const string k_EventTopicName = "usability";
|
||||
|
||||
static bool s_EnableAnalytics = false;
|
||||
|
||||
public static void EnableAnalytics()
|
||||
{
|
||||
AnalyticsResult result = EditorAnalytics.RegisterEventWithLimit(k_EventTopicName, k_MaxEventsPerHour, k_MaxEventItems, k_VendorKey);
|
||||
if (result == AnalyticsResult.Ok)
|
||||
s_EnableAnalytics = true;
|
||||
}
|
||||
|
||||
public enum UIButton
|
||||
{
|
||||
Pull,
|
||||
OpenProfiler,
|
||||
CloseProfiler,
|
||||
JumpToFrame,
|
||||
ExportSingleFrames,
|
||||
ExportComparisonFrames,
|
||||
};
|
||||
|
||||
public enum UIUsageMode
|
||||
{
|
||||
Single,
|
||||
Comparison,
|
||||
};
|
||||
|
||||
public enum UIVisibility
|
||||
{
|
||||
FrameTimeContextMenu,
|
||||
Filters,
|
||||
TopTen,
|
||||
Frames,
|
||||
Threads,
|
||||
Markers,
|
||||
};
|
||||
|
||||
public enum UIResizeView
|
||||
{
|
||||
Single,
|
||||
Comparison,
|
||||
};
|
||||
|
||||
|
||||
[Serializable]
|
||||
struct ProfileAnalyzerUIButtonEventParameters
|
||||
{
|
||||
public string name;
|
||||
|
||||
public ProfileAnalyzerUIButtonEventParameters(string name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
// camelCase since these events get serialized to Json and naming convention in analytics is camelCase
|
||||
[Serializable]
|
||||
struct ProfileAnalyzerUIButtonEvent
|
||||
{
|
||||
public ProfileAnalyzerUIButtonEvent(string name, float durationInTicks)
|
||||
{
|
||||
subtype = "profileAnalyzerUIButton";
|
||||
|
||||
// ts is auto added so no need to include it here
|
||||
//ts = (int)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
|
||||
this.duration = durationInTicks;
|
||||
|
||||
parameters = new ProfileAnalyzerUIButtonEventParameters(name);
|
||||
}
|
||||
|
||||
public string subtype;
|
||||
//public int ts;
|
||||
public float duration; // Duration is in "ticks" 100 nanosecond intervals. I.e. 0.1 microseconds
|
||||
public ProfileAnalyzerUIButtonEventParameters parameters;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
struct ProfileAnalyzerUIUsageEventParameters
|
||||
{
|
||||
public string name;
|
||||
|
||||
public ProfileAnalyzerUIUsageEventParameters(string name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
struct ProfileAnalyzerUIUsageEvent
|
||||
{
|
||||
public ProfileAnalyzerUIUsageEvent(string name, float durationInTicks)
|
||||
{
|
||||
subtype = "profileAnalyzerModeUsage";
|
||||
|
||||
this.duration = durationInTicks;
|
||||
|
||||
parameters = new ProfileAnalyzerUIUsageEventParameters(name);
|
||||
}
|
||||
|
||||
public string subtype;
|
||||
public float duration; // Duration is in "ticks" 100 nanosecond intervals. I.e. 0.1 microseconds
|
||||
public ProfileAnalyzerUIUsageEventParameters parameters;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
struct ProfileAnalyzerUIVisibilityEventParameters
|
||||
{
|
||||
public string name;
|
||||
public bool show;
|
||||
|
||||
public ProfileAnalyzerUIVisibilityEventParameters(string name, bool show)
|
||||
{
|
||||
this.name = name;
|
||||
this.show = show;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
struct ProfileAnalyzerUIVisibilityEvent
|
||||
{
|
||||
public ProfileAnalyzerUIVisibilityEvent(string name, float durationInTicks, bool show)
|
||||
{
|
||||
subtype = "profileAnalyzerUIVisibility";
|
||||
|
||||
this.duration = durationInTicks;
|
||||
|
||||
parameters = new ProfileAnalyzerUIVisibilityEventParameters(name, show);
|
||||
}
|
||||
|
||||
public string subtype;
|
||||
public float duration; // Duration is in "ticks" 100 nanosecond intervals. I.e. 0.1 microseconds
|
||||
public ProfileAnalyzerUIVisibilityEventParameters parameters;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
struct ProfileAnalyzerUIResizeEventParameters
|
||||
{
|
||||
public string name;
|
||||
public float width;
|
||||
public float height;
|
||||
public float screenWidth;
|
||||
public float screenHeight;
|
||||
public bool docked;
|
||||
|
||||
public ProfileAnalyzerUIResizeEventParameters(string name, float width, float height, float screenWidth, float screenHeight, bool isDocked)
|
||||
{
|
||||
this.name = name;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.screenWidth = screenWidth;
|
||||
this.screenHeight = screenHeight;
|
||||
docked = isDocked;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
struct ProfileAnalyzerUIResizeEvent
|
||||
{
|
||||
public ProfileAnalyzerUIResizeEvent(string name, float durationInTicks, float width, float height, float screenWidth, float screenHeight, bool isDocked)
|
||||
{
|
||||
subtype = "profileAnalyzerUIResize";
|
||||
|
||||
this.duration = durationInTicks;
|
||||
|
||||
parameters = new ProfileAnalyzerUIResizeEventParameters(name, width, height, screenWidth, screenHeight, isDocked);
|
||||
}
|
||||
|
||||
public string subtype;
|
||||
public float duration; // Duration is in "ticks" 100 nanosecond intervals. I.e. 0.1 microseconds
|
||||
public ProfileAnalyzerUIResizeEventParameters parameters;
|
||||
}
|
||||
|
||||
static float SecondsToTicks(float durationInSeconds)
|
||||
{
|
||||
return durationInSeconds * 10000;
|
||||
}
|
||||
|
||||
public static bool SendUIButtonEvent(UIButton uiButton, float durationInSeconds)
|
||||
{
|
||||
if (!s_EnableAnalytics)
|
||||
return false;
|
||||
|
||||
// Duration is in "ticks" 100 nanosecond intervals. I.e. 0.1 microseconds
|
||||
float durationInTicks = SecondsToTicks(durationInSeconds);
|
||||
|
||||
ProfileAnalyzerUIButtonEvent uiButtonEvent;
|
||||
switch (uiButton)
|
||||
{
|
||||
case UIButton.Pull:
|
||||
uiButtonEvent = new ProfileAnalyzerUIButtonEvent("profilerAnalyzerGrab", durationInTicks);
|
||||
break;
|
||||
case UIButton.OpenProfiler:
|
||||
uiButtonEvent = new ProfileAnalyzerUIButtonEvent("profilerAnalyzerOpenProfiler", durationInTicks);
|
||||
break;
|
||||
case UIButton.CloseProfiler:
|
||||
uiButtonEvent = new ProfileAnalyzerUIButtonEvent("profilerAnalyzerCloseProfiler", durationInTicks);
|
||||
break;
|
||||
case UIButton.JumpToFrame:
|
||||
uiButtonEvent = new ProfileAnalyzerUIButtonEvent("profilerAnalyzerJumpToFrame", durationInTicks);
|
||||
break;
|
||||
case UIButton.ExportSingleFrames:
|
||||
uiButtonEvent = new ProfileAnalyzerUIButtonEvent("profilerAnalyzerExportSingleFrames", durationInTicks);
|
||||
break;
|
||||
case UIButton.ExportComparisonFrames:
|
||||
uiButtonEvent = new ProfileAnalyzerUIButtonEvent("profilerAnalyzerExportComparisonFrames", durationInTicks);
|
||||
break;
|
||||
default:
|
||||
Debug.LogFormat("SendUIButtonEvent: Unsupported button type : {0}", uiButton);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
AnalyticsResult result = EditorAnalytics.SendEventWithLimit(k_EventTopicName, uiButtonEvent);
|
||||
if (result != AnalyticsResult.Ok)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool SendUIUsageModeEvent(UIUsageMode uiUsageMode, float durationInSeconds)
|
||||
{
|
||||
if (!s_EnableAnalytics)
|
||||
return false;
|
||||
|
||||
// Duration is in "ticks" 100 nanosecond intervals. I.e. 0.1 microseconds
|
||||
float durationInTicks = SecondsToTicks(durationInSeconds);
|
||||
|
||||
ProfileAnalyzerUIUsageEvent uiUsageEvent;
|
||||
switch (uiUsageMode)
|
||||
{
|
||||
case UIUsageMode.Single:
|
||||
uiUsageEvent = new ProfileAnalyzerUIUsageEvent("profileAnalyzerSingle", durationInTicks);
|
||||
break;
|
||||
case UIUsageMode.Comparison:
|
||||
uiUsageEvent = new ProfileAnalyzerUIUsageEvent("profileAnalyzerCompare", durationInTicks);
|
||||
break;
|
||||
default:
|
||||
Debug.LogFormat("SendUsageEvent: Unsupported usage mode : {0}", uiUsageMode);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
AnalyticsResult result = EditorAnalytics.SendEventWithLimit(k_EventTopicName, uiUsageEvent);
|
||||
if (result != AnalyticsResult.Ok)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool SendUIVisibilityEvent(UIVisibility uiVisibility, float durationInSeconds, bool show)
|
||||
{
|
||||
if (!s_EnableAnalytics)
|
||||
return false;
|
||||
|
||||
// Duration is in "ticks" 100 nanosecond intervals. I.e. 0.1 microseconds
|
||||
float durationInTicks = SecondsToTicks(durationInSeconds);
|
||||
|
||||
ProfileAnalyzerUIVisibilityEvent uiUsageEvent;
|
||||
switch (uiVisibility)
|
||||
{
|
||||
case UIVisibility.FrameTimeContextMenu:
|
||||
uiUsageEvent = new ProfileAnalyzerUIVisibilityEvent("profilerAnalyzerFrameTimeContextMenu", durationInTicks, show);
|
||||
break;
|
||||
case UIVisibility.Filters:
|
||||
uiUsageEvent = new ProfileAnalyzerUIVisibilityEvent("profilerAnalyzerFilters", durationInTicks, show);
|
||||
break;
|
||||
case UIVisibility.TopTen:
|
||||
uiUsageEvent = new ProfileAnalyzerUIVisibilityEvent("profilerAnalyzerTopTen", durationInTicks, show);
|
||||
break;
|
||||
case UIVisibility.Frames:
|
||||
uiUsageEvent = new ProfileAnalyzerUIVisibilityEvent("profilerAnalyzerFrames", durationInTicks, show);
|
||||
break;
|
||||
case UIVisibility.Threads:
|
||||
uiUsageEvent = new ProfileAnalyzerUIVisibilityEvent("profilerAnalyzerThreads", durationInTicks, show);
|
||||
break;
|
||||
case UIVisibility.Markers:
|
||||
uiUsageEvent = new ProfileAnalyzerUIVisibilityEvent("profilerAnalyzerMarkers", durationInTicks, show);
|
||||
break;
|
||||
default:
|
||||
Debug.LogFormat("SendUIVisibilityEvent: Unsupported visibililty item : {0}", uiVisibility);
|
||||
return false;
|
||||
}
|
||||
|
||||
AnalyticsResult result = EditorAnalytics.SendEventWithLimit(k_EventTopicName, uiUsageEvent);
|
||||
if (result != AnalyticsResult.Ok)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool SendUIResizeEvent(UIResizeView uiResizeView, float durationInSeconds, float width, float height, bool isDocked)
|
||||
{
|
||||
if (!s_EnableAnalytics)
|
||||
return false;
|
||||
|
||||
// Duration is in "ticks" 100 nanosecond intervals. I.e. 0.1 microseconds
|
||||
float durationInTicks = SecondsToTicks(durationInSeconds);
|
||||
|
||||
ProfileAnalyzerUIResizeEvent uiResizeEvent;
|
||||
switch (uiResizeView)
|
||||
{
|
||||
case UIResizeView.Single:
|
||||
// Screen.width, Screen.height is game view size
|
||||
uiResizeEvent = new ProfileAnalyzerUIResizeEvent("profileAnalyzerSingle", durationInTicks, width, height, Screen.currentResolution.width, Screen.currentResolution.height, isDocked);
|
||||
break;
|
||||
case UIResizeView.Comparison:
|
||||
uiResizeEvent = new ProfileAnalyzerUIResizeEvent("profileAnalyzerCompare", durationInTicks, width, height, Screen.currentResolution.width, Screen.currentResolution.height, isDocked);
|
||||
break;
|
||||
default:
|
||||
Debug.LogFormat("SendUIResizeEvent: Unsupported view : {0}", uiResizeView);
|
||||
return false;
|
||||
}
|
||||
|
||||
AnalyticsResult result = EditorAnalytics.SendEventWithLimit(k_EventTopicName, uiResizeEvent);
|
||||
if (result != AnalyticsResult.Ok)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal class Analytic
|
||||
{
|
||||
double m_StartTime;
|
||||
float m_DurationInSeconds;
|
||||
|
||||
public Analytic()
|
||||
{
|
||||
m_StartTime = EditorApplication.timeSinceStartup;
|
||||
m_DurationInSeconds = 0;
|
||||
}
|
||||
|
||||
public void End()
|
||||
{
|
||||
m_DurationInSeconds = (float)(EditorApplication.timeSinceStartup - m_StartTime);
|
||||
}
|
||||
|
||||
public float GetDurationInSeconds()
|
||||
{
|
||||
return m_DurationInSeconds;
|
||||
}
|
||||
}
|
||||
|
||||
static public Analytic BeginAnalytic()
|
||||
{
|
||||
return new Analytic();
|
||||
}
|
||||
|
||||
static public void SendUIButtonEvent(UIButton uiButton, Analytic instance)
|
||||
{
|
||||
instance.End();
|
||||
SendUIButtonEvent(uiButton, instance.GetDurationInSeconds());
|
||||
}
|
||||
|
||||
static public void SendUIUsageModeEvent(UIUsageMode uiUsageMode, Analytic instance)
|
||||
{
|
||||
instance.End();
|
||||
SendUIUsageModeEvent(uiUsageMode, instance.GetDurationInSeconds());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: adf9820979228054693ce2e8224012fb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,3 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Unity.Performance.Profile-Analyzer.EditorTests")]
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dcb585fc3518ff949912f2d4fff2e26f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,240 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
|
||||
namespace UnityEditor.Performance.ProfileAnalyzer
|
||||
{
|
||||
internal class BoxAndWhiskerPlot
|
||||
{
|
||||
Draw2D m_2D;
|
||||
|
||||
Color m_ColorBackground;
|
||||
DisplayUnits m_Units;
|
||||
|
||||
string DisplayUnits()
|
||||
{
|
||||
return m_Units.Postfix();
|
||||
}
|
||||
|
||||
string ToDisplayUnits(float ms, bool showUnits = false)
|
||||
{
|
||||
return m_Units.ToString(ms, showUnits, 5, true);
|
||||
}
|
||||
|
||||
string ToTooltipDisplayUnits(float ms, bool showUnits = false)
|
||||
{
|
||||
return m_Units.ToTooltipString(ms, showUnits);
|
||||
}
|
||||
|
||||
public void SetUnits(Units units)
|
||||
{
|
||||
m_Units = new DisplayUnits(units);
|
||||
}
|
||||
|
||||
public BoxAndWhiskerPlot(Draw2D draw2D, Units units, Color colorBackground)
|
||||
{
|
||||
m_2D = draw2D;
|
||||
SetUnits(units);
|
||||
m_ColorBackground = colorBackground;
|
||||
}
|
||||
|
||||
public BoxAndWhiskerPlot(Draw2D draw2D, Units units)
|
||||
{
|
||||
m_2D = draw2D;
|
||||
SetUnits(units);
|
||||
m_ColorBackground = new Color(0.4f, 0.4f, 0.4f);
|
||||
}
|
||||
|
||||
float ClampToRange(float value, float min, float max)
|
||||
{
|
||||
return Math.Max(min, Math.Min(value, max));
|
||||
}
|
||||
|
||||
public void Draw(float width, float height, float min, float lowerQuartile, float median, float upperQuartile, float max, float yAxisStart, float yAxisEnd, Color color, Color colorFilled)
|
||||
{
|
||||
if (m_2D.DrawStart(width, height, Draw2D.Origin.BottomLeft))
|
||||
{
|
||||
Rect rect = GUILayoutUtility.GetLastRect();
|
||||
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
float w = width;
|
||||
float h = height;
|
||||
|
||||
Draw(rect, x, y, w, h, min, lowerQuartile, median, upperQuartile, max, yAxisStart, yAxisEnd, color, colorFilled);
|
||||
m_2D.DrawEnd();
|
||||
}
|
||||
}
|
||||
|
||||
string GetTooltip(float min, float lowerQuartile, float median, float upperQuartile, float max)
|
||||
{
|
||||
string tooltip = string.Format(
|
||||
"Max :\t\t{0}\n\nUpper Quartile :\t{1}\nMedian :\t\t{2}\nLower Quartile :\t{3}\nInterquartile range : \t{4}\n\nMin :\t\t{5}\nUnits :\t\t{6}",
|
||||
ToTooltipDisplayUnits(max),
|
||||
ToTooltipDisplayUnits(upperQuartile),
|
||||
ToTooltipDisplayUnits(median),
|
||||
ToTooltipDisplayUnits(lowerQuartile),
|
||||
ToTooltipDisplayUnits(upperQuartile - lowerQuartile),
|
||||
ToTooltipDisplayUnits(min),
|
||||
m_Units.Postfix()
|
||||
);
|
||||
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
public void Draw(Rect rect, float x, float y, float w, float h, float min, float lowerQuartile, float median, float upperQuartile, float max, float yAxisStart, float yAxisEnd, Color color, Color colorFilled, bool clearFirst = true)
|
||||
{
|
||||
string tooltip = GetTooltip(min, lowerQuartile, median, upperQuartile, max);
|
||||
GUI.Label(rect, new GUIContent("", tooltip));
|
||||
|
||||
if (clearFirst)
|
||||
m_2D.DrawFilledBox(x, y, w, h, m_ColorBackground);
|
||||
|
||||
float first = yAxisStart;
|
||||
float last = yAxisEnd;
|
||||
float range = last - first;
|
||||
|
||||
bool startCap = (min >= first) ? true : false;
|
||||
bool endCap = (max <= last) ? true : false;
|
||||
|
||||
// Range clamping
|
||||
min = ClampToRange(min, first, last);
|
||||
lowerQuartile = ClampToRange(lowerQuartile, first, last);
|
||||
median = ClampToRange(median, first, last);
|
||||
upperQuartile = ClampToRange(upperQuartile, first, last);
|
||||
max = ClampToRange(max, first, last);
|
||||
|
||||
float hMax = h - 1;
|
||||
float yMin = hMax * (min - first) / range;
|
||||
float yLowerQuartile = hMax * (lowerQuartile - first) / range;
|
||||
float yMedian = hMax * (median - first) / range;
|
||||
float yUpperQuartile = hMax * (upperQuartile - first) / range;
|
||||
float yMax = hMax * (max - first) / range;
|
||||
|
||||
// Min to max line
|
||||
float xCentre = x + (w / 2);
|
||||
m_2D.DrawLine(xCentre, y + yMin, xCentre, y + yLowerQuartile, color);
|
||||
m_2D.DrawLine(xCentre, y + yUpperQuartile, xCentre, y + yMax, color);
|
||||
|
||||
// Quartile boxes
|
||||
float xMargin = (2 * w / 8);
|
||||
float x1 = x + xMargin;
|
||||
float x2 = x + (w - xMargin);
|
||||
float wBox = x2 - x1;
|
||||
if (colorFilled != color)
|
||||
m_2D.DrawFilledBox(x1, y + yLowerQuartile, wBox, (yMedian - yLowerQuartile), colorFilled);
|
||||
m_2D.DrawBox(x1, y + yLowerQuartile, wBox, (yMedian - yLowerQuartile), color);
|
||||
if (colorFilled != color)
|
||||
m_2D.DrawFilledBox(x1, y + yMedian, wBox, (yUpperQuartile - yMedian), colorFilled);
|
||||
m_2D.DrawBox(x1, y + yMedian, wBox, (yUpperQuartile - yMedian), color);
|
||||
|
||||
// Median line
|
||||
//xMargin = (1 * w / 8);
|
||||
//x1 = x + xMargin;
|
||||
//x2 = x + (w - xMargin);
|
||||
m_2D.DrawLine(x1, y + yMedian, x2, y + yMedian, color);
|
||||
m_2D.DrawLine(x1, y + yMedian + 1, x2, y + yMedian + 1, color);
|
||||
|
||||
// Line caps
|
||||
xMargin = (3 * w / 8);
|
||||
x1 = x + xMargin;
|
||||
x2 = x + (w - xMargin);
|
||||
if (startCap)
|
||||
m_2D.DrawLine(x1, y + yMin, x2, y + yMin, color);
|
||||
|
||||
if (endCap)
|
||||
m_2D.DrawLine(x1, y + yMax, x2, y + yMax, color);
|
||||
}
|
||||
|
||||
public void DrawHorizontal(float width, float height, float min, float lowerQuartile, float median, float upperQuartile, float max, float xAxisStart, float xAxisEnd, Color color, Color colorFilled, GUIStyle style = null)
|
||||
{
|
||||
if (m_2D.DrawStart(width, height, Draw2D.Origin.BottomLeft, style))
|
||||
{
|
||||
Rect rect = GUILayoutUtility.GetLastRect();
|
||||
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
float w = width;
|
||||
float h = height;
|
||||
|
||||
DrawHorizontal(rect, x, y, w, h, min, lowerQuartile, median, upperQuartile, max, xAxisStart, xAxisEnd, color, colorFilled);
|
||||
m_2D.DrawEnd();
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawHorizontal(Rect rect, float x, float y, float w, float h, float min, float lowerQuartile, float median, float upperQuartile, float max, float xAxisStart, float xAxisEnd, Color color, Color colorFilled, bool clearFirst = true)
|
||||
{
|
||||
string tooltip = GetTooltip(min, lowerQuartile, median, upperQuartile, max);
|
||||
GUI.Label(rect, new GUIContent("", tooltip));
|
||||
|
||||
if (clearFirst)
|
||||
m_2D.DrawFilledBox(x, y, w, h, m_ColorBackground);
|
||||
|
||||
float first = xAxisStart;
|
||||
float last = xAxisEnd;
|
||||
float range = last - first;
|
||||
|
||||
bool startCap = (min >= first) ? true : false;
|
||||
bool endCap = (max <= last) ? true : false;
|
||||
|
||||
// Range clamping
|
||||
min = ClampToRange(min, first, last);
|
||||
lowerQuartile = ClampToRange(lowerQuartile, first, last);
|
||||
median = ClampToRange(median, first, last);
|
||||
upperQuartile = ClampToRange(upperQuartile, first, last);
|
||||
max = ClampToRange(max, first, last);
|
||||
|
||||
float xMin = w * (min - first) / range;
|
||||
float xLowerQuartile = w * (lowerQuartile - first) / range;
|
||||
float xMedian = w * (median - first) / range;
|
||||
float xUpperQuartile = w * (upperQuartile - first) / range;
|
||||
float xMax = w * (max - first) / range;
|
||||
|
||||
// Min to max line
|
||||
m_2D.DrawLine(x + xMin, y + (h / 2), x + xMax, y + (h / 2), color);
|
||||
|
||||
// Quartile boxes
|
||||
float yMargin = (2 * h / 8);
|
||||
float y1 = y + yMargin;
|
||||
float y2 = y + (h - yMargin);
|
||||
float hBox = y2 - y1;
|
||||
if (colorFilled != color)
|
||||
m_2D.DrawFilledBox(x + xLowerQuartile, y1, xMedian - xLowerQuartile, hBox, colorFilled);
|
||||
m_2D.DrawBox(x + xLowerQuartile, y1, xMedian - xLowerQuartile, hBox, color);
|
||||
if (colorFilled != color)
|
||||
m_2D.DrawFilledBox(x + xMedian, y1, xUpperQuartile - xMedian, hBox, colorFilled);
|
||||
m_2D.DrawBox(x + xMedian, y1, xUpperQuartile - xMedian, hBox, color);
|
||||
|
||||
// Median line
|
||||
//yMargin = (1 * h / 8);
|
||||
//y1 = y + yMargin;
|
||||
//y2 = y + (h - yMargin);
|
||||
m_2D.DrawLine(x + xMedian, y1, x + xMedian, y2, color);
|
||||
m_2D.DrawLine(x + xMedian + 1, y1, x + xMedian + 1, y2, color);
|
||||
|
||||
// Line caps
|
||||
yMargin = (3 * h / 8);
|
||||
y1 = y + yMargin;
|
||||
y2 = y + (h - yMargin);
|
||||
if (startCap)
|
||||
m_2D.DrawLine(x + xMin, y1, x + xMin, y2, color);
|
||||
|
||||
if (endCap)
|
||||
m_2D.DrawLine(x + xMax, y1, x + xMax, y2, color);
|
||||
}
|
||||
|
||||
public void DrawText(float width, float plotHeight, float min, float max, string minTooltip, string maxTooltip)
|
||||
{
|
||||
GUIStyle shiftUpStyle = new GUIStyle(GUI.skin.label);
|
||||
shiftUpStyle.contentOffset = new Vector2(0, -5);
|
||||
shiftUpStyle.alignment = TextAnchor.UpperLeft;
|
||||
EditorGUILayout.BeginVertical(GUILayout.Height(plotHeight));
|
||||
EditorGUILayout.LabelField(new GUIContent(ToDisplayUnits(max), maxTooltip), shiftUpStyle, GUILayout.Width(width));
|
||||
GUILayout.FlexibleSpace();
|
||||
GUIStyle shiftDownStyle = new GUIStyle(GUI.skin.label);
|
||||
shiftDownStyle.contentOffset = new Vector2(0, 1);
|
||||
shiftDownStyle.alignment = TextAnchor.LowerLeft;
|
||||
EditorGUILayout.LabelField(new GUIContent(ToDisplayUnits(min), minTooltip), shiftDownStyle, GUILayout.Width(width));
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae5c414d7d406467d8ce01807c211f90
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,184 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System;
|
||||
|
||||
namespace UnityEditor.Performance.ProfileAnalyzer
|
||||
{
|
||||
internal class Columns
|
||||
{
|
||||
int[] m_ColumnWidth = new int[4];
|
||||
|
||||
public Columns(int a, int b, int c, int d)
|
||||
{
|
||||
SetColumnSizes(a, b, c, d);
|
||||
}
|
||||
|
||||
public void SetColumnSizes(int a, int b, int c, int d)
|
||||
{
|
||||
m_ColumnWidth[0] = a;
|
||||
m_ColumnWidth[1] = b;
|
||||
m_ColumnWidth[2] = c;
|
||||
m_ColumnWidth[3] = d;
|
||||
}
|
||||
|
||||
public int GetColumnWidth(int n)
|
||||
{
|
||||
if (n < 0 || n >= m_ColumnWidth.Length)
|
||||
return 0;
|
||||
|
||||
return m_ColumnWidth[n];
|
||||
}
|
||||
|
||||
public void Draw(int n, string col)
|
||||
{
|
||||
if (n < 0 || n >= m_ColumnWidth.Length || m_ColumnWidth[n] <= 0)
|
||||
EditorGUILayout.LabelField(col);
|
||||
|
||||
EditorGUILayout.LabelField(col, GUILayout.Width(m_ColumnWidth[n]));
|
||||
}
|
||||
|
||||
public void Draw(int n, float value)
|
||||
{
|
||||
Draw(n, string.Format("{0:f2}", value));
|
||||
}
|
||||
|
||||
public void Draw2(string col1, string col2)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
Draw(0, col1);
|
||||
Draw(1, col2);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void Draw2(string label, float value)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
Draw(0, label);
|
||||
Draw(1, value);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void Draw3(string col1, string col2, string col3)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
Draw(0, col1);
|
||||
Draw(1, col2);
|
||||
Draw(2, col3);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void Draw3(string col1, float value2, float value3)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
Draw(0, col1);
|
||||
Draw(1, value2);
|
||||
Draw(2, value3);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void Draw4(string col1, string col2, string col3, string col4)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
Draw(0, col1);
|
||||
Draw(1, col2);
|
||||
Draw(2, col3);
|
||||
Draw(3, col4);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void Draw4Diff(string col1, float left, float right)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
Draw(0, col1);
|
||||
Draw(1, left);
|
||||
Draw(2, right);
|
||||
Draw(3, right - left);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void Draw4(string col1, float value2, float value3, float value4)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
Draw(0, col1);
|
||||
Draw(1, value2);
|
||||
Draw(2, value3);
|
||||
Draw(3, value4);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
// GUIContent versions
|
||||
public void Draw(int n, GUIContent col)
|
||||
{
|
||||
if (n < 0 || n >= m_ColumnWidth.Length || m_ColumnWidth[n] <= 0)
|
||||
EditorGUILayout.LabelField(col);
|
||||
|
||||
EditorGUILayout.LabelField(col, GUILayout.Width(m_ColumnWidth[n]));
|
||||
}
|
||||
|
||||
public void Draw2(GUIContent col1, GUIContent col2)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
Draw(0, col1);
|
||||
Draw(1, col2);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void Draw2(GUIContent label, float value)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
Draw(0, label);
|
||||
Draw(1, value);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void Draw3(GUIContent col1, GUIContent col2, GUIContent col3)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
Draw(0, col1);
|
||||
Draw(1, col2);
|
||||
Draw(2, col3);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void Draw3(GUIContent col1, float value2, float value3)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
Draw(0, col1);
|
||||
Draw(1, value2);
|
||||
Draw(2, value3);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void Draw4(GUIContent col1, GUIContent col2, GUIContent col3, GUIContent col4)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
Draw(0, col1);
|
||||
Draw(1, col2);
|
||||
Draw(2, col3);
|
||||
Draw(3, col4);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void Draw4Diff(GUIContent col1, float left, float right)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
Draw(0, col1);
|
||||
Draw(1, left);
|
||||
Draw(2, right);
|
||||
Draw(3, right - left);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void Draw4(GUIContent col1, float value2, float value3, float value4)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
Draw(0, col1);
|
||||
Draw(1, value2);
|
||||
Draw(2, value3);
|
||||
Draw(3, value4);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a402cbe9b84984bd4a16cb20ca9c3bed
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 281fa44557d2f417aafc937bd5d93ba5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
|
||||
namespace UnityEditor.Performance.ProfileAnalyzer
|
||||
{
|
||||
class DepthSliceDropdown : AdvancedDropdown
|
||||
{
|
||||
class DepthSliceDropdownItem : AdvancedDropdownItem
|
||||
{
|
||||
public int depthSlice;
|
||||
public int depthSliceLeft;
|
||||
public int depthSliceRight;
|
||||
public DepthSliceDropdownItem(int depthSlice)
|
||||
: base(DepthSliceUI.DepthFilterToString(depthSlice))
|
||||
{
|
||||
this.depthSlice = depthSlice;
|
||||
depthSliceLeft = depthSlice;
|
||||
depthSliceRight = depthSlice;
|
||||
}
|
||||
public DepthSliceDropdownItem(int depthSliceLeft, int depthSliceRight, bool leftIsMain)
|
||||
: base(DepthSliceUI.DepthFilterToString(depthSliceLeft, depthSliceRight, leftIsMain))
|
||||
{
|
||||
depthSlice = Math.Max(depthSliceLeft, depthSliceRight);
|
||||
this.depthSliceLeft = depthSliceLeft;
|
||||
this.depthSliceRight = depthSliceRight;
|
||||
}
|
||||
}
|
||||
|
||||
Action<int, int, int> m_Callback = null;
|
||||
int m_DepthSliceCount;
|
||||
int m_DepthSliceCountRight;
|
||||
int m_CurrentDepthSliceA;
|
||||
int m_CurrentDepthSliceB;
|
||||
int m_DepthDiff;
|
||||
|
||||
static FieldInfo m_DataSourceFieldInfo;
|
||||
static Type m_DataSourceTypeInfo;
|
||||
static PropertyInfo m_SelectedIdsFieldInfo;
|
||||
|
||||
public DepthSliceDropdown(int depthSliceCount, int currentDepthSliceA, int currentDepthSliceB, Action<int, int, int> callback, int depthDiff, int depthSliceCountRight = ProfileAnalyzer.kDepthAll) : base(new AdvancedDropdownState())
|
||||
{
|
||||
m_DepthSliceCount = depthSliceCount;
|
||||
m_DepthSliceCountRight = depthSliceCountRight;
|
||||
m_CurrentDepthSliceA = currentDepthSliceA;
|
||||
m_CurrentDepthSliceB = currentDepthSliceB;
|
||||
m_Callback = callback;
|
||||
m_DepthDiff = depthDiff;
|
||||
if (m_DataSourceFieldInfo == null || m_DataSourceFieldInfo == null || m_SelectedIdsFieldInfo == null)
|
||||
{
|
||||
Assembly assem = typeof(AdvancedDropdown).Assembly;
|
||||
var advancedDropdownTypeInfo = typeof(AdvancedDropdown);
|
||||
m_DataSourceTypeInfo = assem.GetType("UnityEditor.IMGUI.Controls.CallbackDataSource");
|
||||
m_DataSourceFieldInfo = advancedDropdownTypeInfo.GetField("m_DataSource", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
m_SelectedIdsFieldInfo = m_DataSourceTypeInfo.GetProperty("selectedIDs", BindingFlags.Public | BindingFlags.Instance);
|
||||
}
|
||||
}
|
||||
|
||||
protected override AdvancedDropdownItem BuildRoot()
|
||||
{
|
||||
var root = new AdvancedDropdownItem("Depth Slice");
|
||||
var allItem = new DepthSliceDropdownItem(ProfileAnalyzer.kDepthAll);
|
||||
root.AddChild(allItem);
|
||||
if (m_CurrentDepthSliceA == ProfileAnalyzer.kDepthAll && m_CurrentDepthSliceB == ProfileAnalyzer.kDepthAll)
|
||||
(m_SelectedIdsFieldInfo.GetValue(m_DataSourceFieldInfo.GetValue(this)) as List<int>).Add(allItem.id);
|
||||
var count = m_DepthSliceCountRight == ProfileAnalyzer.kDepthAll ? m_DepthSliceCount :
|
||||
Math.Max(m_DepthSliceCount + Math.Max(0, m_DepthDiff), m_DepthSliceCountRight - Math.Min(0, m_DepthDiff));
|
||||
|
||||
var leftIsMain = m_DepthDiff < 0;
|
||||
var mainThreshold = leftIsMain ? m_DepthSliceCount : m_DepthSliceCountRight;
|
||||
var secondaryMinThreshold = Math.Abs(m_DepthDiff);
|
||||
var secondaryMaxThreshold = (leftIsMain ? m_DepthSliceCountRight : m_DepthSliceCount) + secondaryMinThreshold;
|
||||
|
||||
var startIndex = 1;
|
||||
for (int i = startIndex; i <= count; i++)
|
||||
{
|
||||
var selected = false;
|
||||
AdvancedDropdownItem child;
|
||||
if (m_DepthSliceCountRight != ProfileAnalyzer.kDepthAll)
|
||||
{
|
||||
var left = Mathf.Clamp(i - Math.Max(0, m_DepthDiff), 1, m_DepthSliceCount);
|
||||
var right = Mathf.Clamp(i - Math.Max(0, -m_DepthDiff), 1, m_DepthSliceCountRight);
|
||||
|
||||
if (m_DepthSliceCount <= 0)
|
||||
left = -1;
|
||||
else if (m_DepthSliceCountRight <= 0)
|
||||
right = -1;
|
||||
else
|
||||
{
|
||||
// Separators only make sense if there is data on both sides
|
||||
|
||||
// did we pass the threshold of the main's max depth and started clamping it down?
|
||||
if (i == mainThreshold + 1
|
||||
// ... or the threshold of the secondary's negative depth when adjusted for the depth diff, and stoped clamping it up?
|
||||
|| (secondaryMinThreshold != 0 && i == secondaryMinThreshold + 1)
|
||||
// ... or the threshold of the secondary's max depth when adjusted for the depth diff, and started clamping it down?
|
||||
|| (i == secondaryMaxThreshold + 1))
|
||||
root.AddSeparator();
|
||||
}
|
||||
|
||||
child = new DepthSliceDropdownItem(left, right, leftIsMain);
|
||||
selected = m_CurrentDepthSliceA == left && m_CurrentDepthSliceB == right;
|
||||
}
|
||||
else
|
||||
{
|
||||
child = new DepthSliceDropdownItem(i);
|
||||
selected = m_CurrentDepthSliceA == i;
|
||||
}
|
||||
root.AddChild(child);
|
||||
if (selected)
|
||||
(m_SelectedIdsFieldInfo.GetValue(m_DataSourceFieldInfo.GetValue(this)) as List<int>).Add(child.id);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
protected override void ItemSelected(AdvancedDropdownItem item)
|
||||
{
|
||||
base.ItemSelected(item);
|
||||
if (m_Callback != null)
|
||||
{
|
||||
var sliceItem = (item as DepthSliceDropdownItem);
|
||||
m_Callback(sliceItem.depthSlice, sliceItem.depthSliceLeft, sliceItem.depthSliceRight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71b9e5c19de243c386bd048443d1c5cc
|
||||
timeCreated: 1608205585
|
@@ -0,0 +1,460 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Video;
|
||||
|
||||
namespace UnityEditor.Performance.ProfileAnalyzer
|
||||
{
|
||||
[Serializable]
|
||||
public class DepthSliceUI
|
||||
{
|
||||
[SerializeField] int m_DepthFilter = ProfileAnalyzer.kDepthAll;
|
||||
public int depthFilter {get { return m_DepthFilter; }}
|
||||
|
||||
[SerializeField] int m_DepthFilter1 = ProfileAnalyzer.kDepthAll;
|
||||
public int depthFilter1 {get { return m_DepthFilter1; }}
|
||||
|
||||
[SerializeField] int m_DepthFilter2 = ProfileAnalyzer.kDepthAll;
|
||||
public int depthFilter2 {get { return m_DepthFilter2; }}
|
||||
|
||||
[SerializeField] bool m_DepthFilterAuto = true;
|
||||
|
||||
[SerializeField] int m_MostCommonDepthDiff = 0;
|
||||
|
||||
int mostCommonDepthDiff
|
||||
{
|
||||
set
|
||||
{
|
||||
if (m_MostCommonDepthDiff != value)
|
||||
{
|
||||
m_MostCommonDepthDiff = value;
|
||||
UpdateAutoDepthTitleText();
|
||||
}
|
||||
}
|
||||
get
|
||||
{
|
||||
return m_MostCommonDepthDiff;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAutoDepthTitleText()
|
||||
{
|
||||
ProfileAnalyzerWindow.Styles.autoDepthTitle.text =
|
||||
string.Format(ProfileAnalyzerWindow.Styles.autoDepthTitleText, mostCommonDepthDiff);
|
||||
}
|
||||
|
||||
Action<bool> m_UpdateActiveTabCallback = null;
|
||||
public DepthSliceUI(Action<bool> updateActiveTabCallback)
|
||||
{
|
||||
m_UpdateActiveTabCallback = updateActiveTabCallback;
|
||||
UpdateAutoDepthTitleText();
|
||||
}
|
||||
|
||||
public void OnEnable(Action<bool> updateActiveTabCallback)
|
||||
{
|
||||
m_UpdateActiveTabCallback = updateActiveTabCallback;
|
||||
UpdateAutoDepthTitleText();
|
||||
}
|
||||
|
||||
enum ViewType
|
||||
{
|
||||
Single,
|
||||
Left,
|
||||
Right,
|
||||
Locked,
|
||||
}
|
||||
void DrawDepthFilterDropdown(GUIContent title, bool enabled, ProfileDataView view, Action<int, int, int> callback,
|
||||
ViewType viewType, ProfileDataView profileSingleView, ProfileDataView profileLeftView, ProfileDataView profileRightView)
|
||||
{
|
||||
if(title !=null)
|
||||
EditorGUILayout.LabelField(title, GUILayout.Width(ProfileAnalyzerWindow.LayoutSize.FilterOptionsEnumWidth));
|
||||
|
||||
int depthFilter = ProfileAnalyzer.kDepthAll;
|
||||
int depthFilterOther = ProfileAnalyzer.kDepthAll;
|
||||
var maxDepth = view.GetMaxDepth();
|
||||
var maxDepthLeft = ProfileAnalyzer.kDepthAll;
|
||||
var maxDepthRight = ProfileAnalyzer.kDepthAll;
|
||||
|
||||
var oldDepthFilter = ProfileAnalyzer.kDepthAll;
|
||||
var oldDepthFilterOtherLocked = ProfileAnalyzer.kDepthAll;
|
||||
var depthDiff = mostCommonDepthDiff;
|
||||
GUIContent content;
|
||||
switch (viewType)
|
||||
{
|
||||
case ViewType.Single:
|
||||
oldDepthFilter = m_DepthFilter;
|
||||
depthFilter = m_DepthFilter =
|
||||
m_DepthFilter == ProfileAnalyzer.kDepthAll ?
|
||||
ProfileAnalyzer.kDepthAll :
|
||||
profileSingleView.ClampToValidDepthValue(m_DepthFilter);
|
||||
content = new GUIContent(DepthFilterToString(depthFilter));
|
||||
depthFilterOther = depthFilter;
|
||||
depthDiff = 0;
|
||||
break;
|
||||
case ViewType.Left:
|
||||
oldDepthFilter = m_DepthFilter1;
|
||||
depthFilter = m_DepthFilter1 =
|
||||
m_DepthFilter1 == ProfileAnalyzer.kDepthAll ?
|
||||
ProfileAnalyzer.kDepthAll :
|
||||
profileLeftView.ClampToValidDepthValue(m_DepthFilter1);
|
||||
content = new GUIContent(DepthFilterToString(depthFilter));
|
||||
depthFilterOther = depthFilter;
|
||||
break;
|
||||
case ViewType.Right:
|
||||
oldDepthFilter = m_DepthFilter2;
|
||||
depthFilter = m_DepthFilter2 = m_DepthFilter2 == ProfileAnalyzer.kDepthAll
|
||||
? ProfileAnalyzer.kDepthAll
|
||||
: profileRightView.ClampToValidDepthValue(m_DepthFilter2);
|
||||
content = new GUIContent(DepthFilterToString(depthFilter));
|
||||
depthFilterOther = depthFilter;
|
||||
break;
|
||||
case ViewType.Locked:
|
||||
oldDepthFilter = m_DepthFilter1;
|
||||
oldDepthFilterOtherLocked = m_DepthFilter2;
|
||||
maxDepth = maxDepthLeft = profileLeftView.GetMaxDepth();
|
||||
maxDepthRight = profileRightView.GetMaxDepth();
|
||||
|
||||
ClampDepthFilterForAutoRespectingDiff(ref m_DepthFilter1, ref m_DepthFilter2, profileLeftView, profileRightView);
|
||||
|
||||
depthFilter = m_DepthFilter1;
|
||||
depthFilterOther = m_DepthFilter2;
|
||||
content = new GUIContent(DepthFilterToString(m_DepthFilter1, m_DepthFilter2, mostCommonDepthDiff < 0));
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
var lastEnabled = GUI.enabled;
|
||||
GUI.enabled = enabled;
|
||||
var rect = GUILayoutUtility.GetRect(content, EditorStyles.popup, GUILayout.MinWidth(ProfileAnalyzerWindow.LayoutSize.FilterOptionsEnumWidth));
|
||||
if (GUI.Button(rect, content, EditorStyles.popup))
|
||||
{
|
||||
var dropdown = new DepthSliceDropdown(maxDepth, depthFilter, depthFilterOther, (slice, left, right) =>
|
||||
{
|
||||
if (slice != depthFilter || (viewType == ViewType.Locked && (left != m_DepthFilter1 || right != m_DepthFilter2)))
|
||||
{
|
||||
callback(slice, left, right);
|
||||
UpdateDepthFilters(viewType == ViewType.Single, profileSingleView, profileLeftView, profileRightView);
|
||||
m_UpdateActiveTabCallback(true);
|
||||
}
|
||||
}, depthDiff, maxDepthRight);
|
||||
dropdown.Show(rect);
|
||||
EditorGUIUtility.ExitGUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
// The depths can change because the data changed, not just because the user selected a different option in the dropdown
|
||||
// in that case, the depth filters need to perform a refresh
|
||||
if(oldDepthFilter != depthFilter || viewType == ViewType.Locked && oldDepthFilterOtherLocked != depthFilterOther)
|
||||
{
|
||||
UpdateDepthFilters(viewType == ViewType.Single, profileSingleView, profileLeftView, profileRightView);
|
||||
m_UpdateActiveTabCallback(true);
|
||||
}
|
||||
}
|
||||
GUI.enabled = lastEnabled;
|
||||
}
|
||||
|
||||
int CalcSliceMenuEntryIndex(int filterDepthLeft, int filterDepthRight, int leftMax, int rightMax)
|
||||
{
|
||||
return mostCommonDepthDiff > 0 ?
|
||||
filterDepthRight + Math.Max(0, filterDepthLeft - rightMax + (rightMax > 0 ? mostCommonDepthDiff : filterDepthLeft > 0 ? 1 : 0)) :
|
||||
filterDepthLeft + Math.Max(0, filterDepthRight - leftMax - (leftMax > 0 ? mostCommonDepthDiff : filterDepthRight > 0 ? -1 :0));
|
||||
}
|
||||
|
||||
void CalcAutoSlicesFromMenuEntryIndex(int depthSlcieMenuEntryIndex, ref int filterDepthLeft, ref int filterDepthRight, int leftMax, int rightMax)
|
||||
{
|
||||
if (mostCommonDepthDiff > 0)
|
||||
{
|
||||
filterDepthRight = Mathf.Clamp(depthSlcieMenuEntryIndex, 1, rightMax);
|
||||
filterDepthLeft = Mathf.Clamp(depthSlcieMenuEntryIndex - (rightMax > 0 ? mostCommonDepthDiff : 0), 1, leftMax);
|
||||
}
|
||||
else
|
||||
{
|
||||
filterDepthLeft = Mathf.Clamp(depthSlcieMenuEntryIndex, 1, leftMax);
|
||||
filterDepthRight = Mathf.Clamp(depthSlcieMenuEntryIndex + (leftMax > 0 ? mostCommonDepthDiff : 0), 1, rightMax);
|
||||
}
|
||||
// if a side has no depth, only allow All
|
||||
if (leftMax <= 0)
|
||||
filterDepthLeft = -1;
|
||||
if (rightMax <= 0)
|
||||
filterDepthRight = -1;
|
||||
}
|
||||
|
||||
void ClampDepthFilterForAutoRespectingDiff(ref int filterDepthLeft, ref int filterDepthRight, ProfileDataView profileLeftView, ProfileDataView profileRightView)
|
||||
{
|
||||
if (filterDepthLeft == ProfileAnalyzer.kDepthAll && filterDepthRight == ProfileAnalyzer.kDepthAll)
|
||||
{
|
||||
// nothing to do here, keep showing all
|
||||
return;
|
||||
}
|
||||
|
||||
var leftMax = profileLeftView.GetMaxDepth();
|
||||
var rightMax = profileRightView.GetMaxDepth();
|
||||
|
||||
var sliceMenuEntryIndex = CalcSliceMenuEntryIndex(filterDepthLeft, filterDepthRight, leftMax, rightMax);
|
||||
CalcAutoSlicesFromMenuEntryIndex(sliceMenuEntryIndex, ref filterDepthLeft, ref filterDepthRight, leftMax, rightMax);
|
||||
}
|
||||
|
||||
internal void DrawDepthFilter(bool isAnalysisRunning, bool singleView,
|
||||
ProfileDataView profileSingleView, ProfileDataView profileLeftView, ProfileDataView profileRightView)
|
||||
{
|
||||
bool lastEnabled = GUI.enabled;
|
||||
bool enabled = !isAnalysisRunning;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (singleView)
|
||||
{
|
||||
EditorGUILayout.LabelField(ProfileAnalyzerWindow.Styles.depthTitle, GUILayout.Width(ProfileAnalyzerWindow.LayoutSize.FilterOptionsLeftLabelWidth));
|
||||
DrawDepthFilterDropdown(null, enabled,
|
||||
profileSingleView, (primary, left, right) => m_DepthFilter = primary,
|
||||
ViewType.Single, profileSingleView, profileLeftView, profileRightView);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField(ProfileAnalyzerWindow.Styles.depthTitle, GUILayout.Width(ProfileAnalyzerWindow.LayoutSize.FilterOptionsLeftLabelWidth));
|
||||
|
||||
if (m_DepthFilterAuto)
|
||||
{
|
||||
DrawDepthFilterDropdown(null, enabled, profileLeftView, (primary, left, right) =>
|
||||
{
|
||||
m_DepthFilter1 = left;
|
||||
m_DepthFilter2 = right;
|
||||
ClampDepthFilterForAutoRespectingDiff(ref m_DepthFilter1, ref m_DepthFilter2, profileLeftView, profileRightView);
|
||||
},
|
||||
ViewType.Locked, profileSingleView, profileLeftView, profileRightView);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
DrawDepthFilterDropdown(ProfileAnalyzerWindow.Styles.leftDepthTitle, enabled, profileLeftView,
|
||||
(primary, left, right) => m_DepthFilter1 = primary,
|
||||
ViewType.Left, profileSingleView, profileLeftView, profileRightView);
|
||||
|
||||
DrawDepthFilterDropdown(ProfileAnalyzerWindow.Styles.rightDepthTitle, enabled && !m_DepthFilterAuto, profileRightView,
|
||||
(primary, left, right) => m_DepthFilter2 = primary,
|
||||
ViewType.Right, profileSingleView, profileLeftView, profileRightView);
|
||||
}
|
||||
bool lastDepthFilterLock = m_DepthFilterAuto;
|
||||
GUI.enabled = enabled;
|
||||
m_DepthFilterAuto = EditorGUILayout.ToggleLeft(ProfileAnalyzerWindow.Styles.autoDepthTitle, m_DepthFilterAuto);
|
||||
GUI.enabled = lastEnabled;
|
||||
if (m_DepthFilterAuto != lastDepthFilterLock)
|
||||
{
|
||||
if (UpdateDepthFilters(singleView, profileSingleView, profileLeftView, profileRightView))
|
||||
m_UpdateActiveTabCallback(true);
|
||||
}
|
||||
}
|
||||
GUILayout.FlexibleSpace();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
internal bool UpdateDepthFilters(bool singleView, ProfileDataView profileSingleView, ProfileDataView profileLeftView, ProfileDataView profileRightView)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
if (!singleView)
|
||||
{
|
||||
// First respect the auto flag
|
||||
if (UpdateAutoDepthFilter(profileLeftView, profileRightView))
|
||||
changed = true;
|
||||
|
||||
// Make sure Single matches the updated comparison view
|
||||
if (profileLeftView.path == profileSingleView.path)
|
||||
{
|
||||
// Use same filter on single view if its the same file
|
||||
if (m_DepthFilter != m_DepthFilter1)
|
||||
{
|
||||
m_DepthFilter = m_DepthFilter1;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (profileRightView.path == profileSingleView.path)
|
||||
{
|
||||
// Use same filter on single view if its the same file
|
||||
if (m_DepthFilter != m_DepthFilter2)
|
||||
{
|
||||
m_DepthFilter = m_DepthFilter2;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure comparisons match updated single view
|
||||
if (profileLeftView.path == profileSingleView.path)
|
||||
{
|
||||
// Use same filter on comparison left view if its the same file
|
||||
if (m_DepthFilter1 != m_DepthFilter)
|
||||
{
|
||||
m_DepthFilter1 = m_DepthFilter;
|
||||
changed = true;
|
||||
}
|
||||
if (m_DepthFilterAuto)
|
||||
{
|
||||
var newDepthFilter2 = m_DepthFilter;
|
||||
ClampDepthFilterForAutoRespectingDiff(ref m_DepthFilter1, ref newDepthFilter2, profileLeftView, profileRightView);
|
||||
|
||||
if (m_DepthFilter2 != newDepthFilter2)
|
||||
{
|
||||
m_DepthFilter2 = newDepthFilter2;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (UpdateAutoDepthFilter(profileLeftView, profileRightView))
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (UpdateAutoDepthFilter(profileLeftView, profileRightView))
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (profileRightView.path == profileSingleView.path)
|
||||
{
|
||||
// Use same filter on comparison right view if its the same file
|
||||
if (m_DepthFilter2 != m_DepthFilter)
|
||||
{
|
||||
m_DepthFilter2 = m_DepthFilter;
|
||||
changed = true;
|
||||
}
|
||||
if (m_DepthFilterAuto)
|
||||
{
|
||||
var newDepthFilter1 = m_DepthFilter;
|
||||
ClampDepthFilterForAutoRespectingDiff(ref newDepthFilter1, ref m_DepthFilter2, profileLeftView, profileRightView);
|
||||
if (m_DepthFilter1 != newDepthFilter1)
|
||||
{
|
||||
m_DepthFilter1 = newDepthFilter1;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (UpdateAutoDepthFilter(profileLeftView, profileRightView))
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
int CalculateDepthDifference(ProfileAnalysis leftAnalysis, ProfileAnalysis rightAnalysis, List<MarkerPairing> pairings)
|
||||
{
|
||||
if (pairings.Count <= 0)
|
||||
{
|
||||
mostCommonDepthDiff = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
var leftMarkers = leftAnalysis.GetMarkers();
|
||||
var rightMarkers = rightAnalysis.GetMarkers();
|
||||
|
||||
int totalCount = 0;
|
||||
Dictionary<int, int> depthDifferences = new Dictionary<int, int>();
|
||||
foreach (var pairing in pairings)
|
||||
{
|
||||
if (pairing.leftIndex >= 0 && pairing.rightIndex >= 0)
|
||||
{
|
||||
MarkerData leftMarker = leftMarkers[pairing.leftIndex];
|
||||
MarkerData rightMarker = rightMarkers[pairing.rightIndex];
|
||||
int markerDepthDiff = rightMarker.minDepth - leftMarker.minDepth;
|
||||
|
||||
int value = 0;
|
||||
depthDifferences.TryGetValue(markerDepthDiff, out value);
|
||||
depthDifferences[markerDepthDiff] = value + 1;
|
||||
totalCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
var newDepthDiff = 0;
|
||||
|
||||
// Find most common depth difference
|
||||
int maxCount = 0;
|
||||
foreach (var diff in depthDifferences.Keys)
|
||||
{
|
||||
if (depthDifferences[diff] > maxCount)
|
||||
{
|
||||
maxCount = depthDifferences[diff];
|
||||
newDepthDiff = diff;
|
||||
}
|
||||
}
|
||||
|
||||
return mostCommonDepthDiff = newDepthDiff;
|
||||
}
|
||||
|
||||
bool UpdateAutoDepthFilter(ProfileDataView profileLeftView, ProfileDataView profileRightView)
|
||||
{
|
||||
if (m_DepthFilterAuto)
|
||||
{
|
||||
var newDepthFilter1 = m_DepthFilter1;
|
||||
var newDepthFilter2 = m_DepthFilter2;
|
||||
ClampDepthFilterForAutoRespectingDiff(ref newDepthFilter1, ref newDepthFilter2, profileLeftView, profileRightView);
|
||||
if (m_DepthFilter1 != newDepthFilter1)
|
||||
{
|
||||
m_DepthFilter1 = newDepthFilter1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_DepthFilter2 != newDepthFilter2)
|
||||
{
|
||||
m_DepthFilter2 = newDepthFilter2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal bool UpdateDepthForCompareSync(ProfileAnalysis leftAnalysis, ProfileAnalysis rightAnalysis, List<MarkerPairing> pairings, ProfileDataView profileLeftView, ProfileDataView profileRightView)
|
||||
{
|
||||
int originalDepthDiff = mostCommonDepthDiff;
|
||||
int newDepthDiff = CalculateDepthDifference(leftAnalysis, rightAnalysis, pairings);
|
||||
if (newDepthDiff != originalDepthDiff)
|
||||
{
|
||||
UpdateAutoDepthFilter(profileLeftView, profileRightView);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal GUIContent GetUIInfo(bool compare)
|
||||
{
|
||||
GUIContent info;
|
||||
if (compare && m_DepthFilter1 == ProfileAnalyzer.kDepthAll && m_DepthFilter2 == ProfileAnalyzer.kDepthAll ||
|
||||
!compare && depthFilter == ProfileAnalyzer.kDepthAll)
|
||||
{
|
||||
info = new GUIContent("(All depths)", string.Format("{0}\n\nSet depth 1 to get an overview of the frame", ProfileAnalyzerWindow.Styles.medianFrameTooltip));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (compare && depthFilter1 != depthFilter2)
|
||||
{
|
||||
if (m_DepthFilter1 == ProfileAnalyzer.kDepthAll)
|
||||
info = new GUIContent(string.Format("(Filtered to 'all' depths in the first data set, and depth '{0}' in the second)", m_DepthFilter2), ProfileAnalyzerWindow.Styles.medianFrameTooltip);
|
||||
else if (m_DepthFilter2 == ProfileAnalyzer.kDepthAll)
|
||||
info = new GUIContent(string.Format("(Filtered to depth '{0}' in the first data set, and 'all' depths in the second)", m_DepthFilter1), ProfileAnalyzerWindow.Styles.medianFrameTooltip);
|
||||
else
|
||||
info = new GUIContent(string.Format("(Filtered to depth '{0}' in the first data set, and depth '{1}' in the second)", m_DepthFilter1, depthFilter2), ProfileAnalyzerWindow.Styles.medianFrameTooltip);
|
||||
}
|
||||
else
|
||||
info = new GUIContent(string.Format("(Filtered to depth '{0}' only)", compare ? m_DepthFilter1 : depthFilter), ProfileAnalyzerWindow.Styles.medianFrameTooltip);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
public static string DepthFilterToString(int depthFilter)
|
||||
{
|
||||
return depthFilter == ProfileAnalyzer.kDepthAll ? "All" : depthFilter.ToString();
|
||||
}
|
||||
|
||||
public static string DepthFilterToString(int depthSliceLeft, int depthSliceRight, bool leftIsMain)
|
||||
{
|
||||
if(depthSliceLeft != depthSliceRight)
|
||||
{
|
||||
if (leftIsMain)
|
||||
return string.Format("{0} ({1}{2})", DepthFilterToString(depthSliceLeft), ProfileAnalyzerWindow.Styles.rightDepthTitle.text, DepthFilterToString(depthSliceRight));
|
||||
else
|
||||
return string.Format("{0} ({1}{2})", DepthFilterToString(depthSliceRight), ProfileAnalyzerWindow.Styles.leftDepthTitle.text, DepthFilterToString(depthSliceLeft));
|
||||
}
|
||||
return DepthFilterToString(depthSliceLeft);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d4bf3d974bf4f74a15e72b2e0a8ffa2
|
||||
timeCreated: 1608212438
|
@@ -0,0 +1,210 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Performance.ProfileAnalyzer
|
||||
{
|
||||
internal class Draw2D
|
||||
{
|
||||
public enum Origin
|
||||
{
|
||||
TopLeft,
|
||||
BottomLeft
|
||||
};
|
||||
|
||||
Origin m_Origin = Origin.TopLeft;
|
||||
GUIStyle m_GLStyle;
|
||||
string m_ShaderName;
|
||||
Material m_Material;
|
||||
Rect m_Rect;
|
||||
Vector4 m_ClipRect;
|
||||
bool m_ClipRectEnabled = false;
|
||||
|
||||
public Draw2D(string shaderName)
|
||||
{
|
||||
m_ShaderName = shaderName;
|
||||
CheckAndSetupMaterial();
|
||||
}
|
||||
|
||||
public bool CheckAndSetupMaterial()
|
||||
{
|
||||
if (m_Material == null)
|
||||
{
|
||||
var shader = Shader.Find(m_ShaderName);
|
||||
if (shader == null)
|
||||
{
|
||||
Debug.LogFormat("Unable to locate shader {0}", m_ShaderName);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Material = new Material(shader);
|
||||
if (m_Material == null)
|
||||
{
|
||||
Debug.LogFormat("Unable to create material for {0}", m_ShaderName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsMaterialValid()
|
||||
{
|
||||
if (m_Material == null)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
if (m_GLStyle == null)
|
||||
{
|
||||
m_GLStyle = new GUIStyle(GUI.skin.box);
|
||||
m_GLStyle.padding = new RectOffset(0, 0, 0, 0);
|
||||
m_GLStyle.margin = new RectOffset(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetClipRect(Rect clipRect)
|
||||
{
|
||||
m_ClipRect = new Vector4(clipRect.x, clipRect.y, clipRect.x + clipRect.width, clipRect.y + clipRect.height);
|
||||
m_ClipRectEnabled = true;
|
||||
|
||||
if (CheckAndSetupMaterial())
|
||||
{
|
||||
m_Material.SetFloat("_UseClipRect", m_ClipRectEnabled ? 1f : 0f);
|
||||
m_Material.SetVector("_ClipRect", m_ClipRect);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearClipRect()
|
||||
{
|
||||
m_ClipRectEnabled = false;
|
||||
|
||||
if (CheckAndSetupMaterial())
|
||||
{
|
||||
m_Material.SetFloat("_UseClipRect", m_ClipRectEnabled ? 1f : 0f);
|
||||
m_Material.SetVector("_ClipRect", m_ClipRect);
|
||||
}
|
||||
}
|
||||
|
||||
public Rect GetClipRect()
|
||||
{
|
||||
return new Rect(m_ClipRect.x, m_ClipRect.y, m_ClipRect.z - m_ClipRect.x, m_ClipRect.w - m_ClipRect.y);
|
||||
}
|
||||
|
||||
public bool DrawStart(Rect r, Origin origin = Origin.TopLeft)
|
||||
{
|
||||
if (Event.current.type != EventType.Repaint)
|
||||
return false;
|
||||
|
||||
if (!CheckAndSetupMaterial())
|
||||
return false;
|
||||
|
||||
m_Material.SetPass(0);
|
||||
|
||||
m_Rect = r;
|
||||
m_Origin = origin;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool DrawStart(float w, float h, Origin origin = Origin.TopLeft, GUIStyle style = null)
|
||||
{
|
||||
Rect r = GUILayoutUtility.GetRect(w, h, style == null ? m_GLStyle : style, GUILayout.ExpandWidth(false), GUILayout.ExpandHeight(false));
|
||||
return DrawStart(r, origin);
|
||||
}
|
||||
|
||||
public void DrawEnd()
|
||||
{
|
||||
}
|
||||
|
||||
public void Translate(ref float x, ref float y)
|
||||
{
|
||||
// Translation done CPU side so we have world space coords in the shader for clipping.
|
||||
if (m_Origin == Origin.BottomLeft)
|
||||
{
|
||||
x = m_Rect.xMin + x;
|
||||
y = m_Rect.yMax - y;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = m_Rect.xMin + x;
|
||||
y = m_Rect.yMin + y;
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawFilledBox(float x, float y, float w, float h, Color col)
|
||||
{
|
||||
float x2 = x + w;
|
||||
float y2 = y + h;
|
||||
|
||||
Translate(ref x, ref y);
|
||||
Translate(ref x2, ref y2);
|
||||
|
||||
if (m_Origin == Origin.BottomLeft)
|
||||
{
|
||||
GL.Begin(GL.TRIANGLE_STRIP);
|
||||
GL.Color(col);
|
||||
GL.Vertex3(x, y, 0);
|
||||
GL.Vertex3(x, y2, 0);
|
||||
GL.Vertex3(x2, y, 0);
|
||||
GL.Vertex3(x2, y2, 0);
|
||||
GL.End();
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.Begin(GL.TRIANGLE_STRIP);
|
||||
GL.Color(col);
|
||||
GL.Vertex3(x, y, 0);
|
||||
GL.Vertex3(x2, y, 0);
|
||||
GL.Vertex3(x, y2, 0);
|
||||
GL.Vertex3(x2, y2, 0);
|
||||
GL.End();
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawFilledBox(float x, float y, float w, float h, float r, float g, float b)
|
||||
{
|
||||
DrawFilledBox(x, y, w, h, new Color(r, g, b));
|
||||
}
|
||||
|
||||
public void DrawLine(float x, float y, float x2, float y2, Color col)
|
||||
{
|
||||
Translate(ref x, ref y);
|
||||
Translate(ref x2, ref y2);
|
||||
|
||||
GL.Begin(GL.LINES);
|
||||
GL.Color(col);
|
||||
GL.Vertex3(x, y, 0);
|
||||
GL.Vertex3(x2, y2, 0);
|
||||
GL.End();
|
||||
}
|
||||
|
||||
public void DrawLine(float x, float y, float x2, float y2, float r, float g, float b)
|
||||
{
|
||||
DrawLine(x, y, x2, y2, new Color(r, g, b));
|
||||
}
|
||||
|
||||
public void DrawBox(float x, float y, float w, float h, Color col)
|
||||
{
|
||||
float x2 = x + w;
|
||||
float y2 = y + h;
|
||||
|
||||
Translate(ref x, ref y);
|
||||
Translate(ref x2, ref y2);
|
||||
|
||||
GL.Begin(GL.LINE_STRIP);
|
||||
GL.Color(col);
|
||||
GL.Vertex3(x, y, 0);
|
||||
GL.Vertex3(x2, y, 0);
|
||||
GL.Vertex3(x2, y2, 0);
|
||||
GL.Vertex3(x, y2, 0);
|
||||
GL.Vertex3(x, y, 0);
|
||||
GL.End();
|
||||
}
|
||||
|
||||
public void DrawBox(float x, float y, float w, float h, float r, float g, float b)
|
||||
{
|
||||
DrawBox(x, y, w, h, new Color(r, g, b));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c27a543a692ef4bf19459f25898a0ba9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEditor.Performance.ProfileAnalyzer
|
||||
{
|
||||
[Serializable]
|
||||
internal class FrameSummary
|
||||
{
|
||||
public double msTotal;
|
||||
public int first;
|
||||
public int last;
|
||||
public int count; // Valid frame count may not be last-first
|
||||
|
||||
public float msMean;
|
||||
public float msMedian;
|
||||
public float msLowerQuartile;
|
||||
public float msUpperQuartile;
|
||||
public float msMin;
|
||||
public float msMax;
|
||||
|
||||
public int medianFrameIndex;
|
||||
public int minFrameIndex;
|
||||
public int maxFrameIndex;
|
||||
|
||||
public int maxMarkerDepth;
|
||||
public int totalMarkers;
|
||||
public int markerCountMax; // Largest marker count (over all frames)
|
||||
public float markerCountMaxMean; // Largest marker count mean
|
||||
|
||||
public int[] buckets = new int[20]; // Each bucket contains 'number of frames' for frametime in that range
|
||||
public List<FrameTime> frames = new List<FrameTime>();
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af62f7ba5c15e47ceb426c7745e31835
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
|
||||
namespace UnityEditor.Performance.ProfileAnalyzer
|
||||
{
|
||||
[Serializable]
|
||||
/// <summary>
|
||||
/// Metrics related to an individual frame
|
||||
/// </summary>
|
||||
internal struct FrameTime : IComparable<FrameTime>
|
||||
{
|
||||
/// <summary>Duration in the frame in milliseconds</summary>
|
||||
public float ms;
|
||||
/// <summary>Index of which frame this time duration occured on. A zero based frame index</summary>
|
||||
public int frameIndex;
|
||||
/// <summary>Number of occurrences</summary>
|
||||
public int count;
|
||||
|
||||
/// <summary>Initialise FrameTime</summary>
|
||||
/// <param name="index"> The frame index</param>
|
||||
/// <param name="msTime"> The duration of the frame in milliseconds</param>
|
||||
/// <param name="_count"> The number of occurrences</param>
|
||||
public FrameTime(int index, float msTime, int _count)
|
||||
{
|
||||
frameIndex = index;
|
||||
ms = msTime;
|
||||
count = _count;
|
||||
}
|
||||
|
||||
/// <summary>Initialise from another FrameTime</summary>
|
||||
/// <param name="t"> The FrameTime to assign</param>
|
||||
public FrameTime(FrameTime t)
|
||||
{
|
||||
frameIndex = t.frameIndex;
|
||||
ms = t.ms;
|
||||
count = t.count;
|
||||
}
|
||||
|
||||
/// <summary>Compare the time duration between the frames. Used for sorting in ascending order</summary>
|
||||
/// <param name="other"> The other FrameTime to compare </param>
|
||||
/// <returns>-1 if this is smaller, 0 if the same, 1 if this is larger</returns>
|
||||
public int CompareTo(FrameTime other)
|
||||
{
|
||||
if (ms == other.ms)
|
||||
{
|
||||
// secondary sort by frame index order
|
||||
return frameIndex.CompareTo(other.frameIndex);
|
||||
}
|
||||
|
||||
return ms.CompareTo(other.ms);
|
||||
}
|
||||
|
||||
/// <summary>Compare the time duration between two FrameTimes. Used for sorting in ascending order</summary>
|
||||
/// <param name="a"> The first FrameTime to compare </param>
|
||||
/// <param name="b"> The second FrameTime to compare </param>
|
||||
/// <returns>-1 if a is smaller, 0 if the same, 1 if a is larger</returns>
|
||||
public static int CompareMs(FrameTime a, FrameTime b)
|
||||
{
|
||||
if (a.ms == b.ms)
|
||||
{
|
||||
// secondary sort by frame index order
|
||||
return a.frameIndex.CompareTo(b.frameIndex);
|
||||
}
|
||||
|
||||
return a.ms.CompareTo(b.ms);
|
||||
}
|
||||
|
||||
/// <summary>Compare the instance count between two FrameTimes. Used for sorting in ascending order</summary>
|
||||
/// <param name="a"> The first FrameTime to compare </param>
|
||||
/// <param name="b"> The second FrameTime to compare </param>
|
||||
/// <returns>-1 if a is smaller, 0 if the same, 1 if a is larger</returns>
|
||||
public static int CompareCount(FrameTime a, FrameTime b)
|
||||
{
|
||||
if (a.count == b.count)
|
||||
{
|
||||
// secondary sort by frame index order
|
||||
return a.frameIndex.CompareTo(b.frameIndex);
|
||||
}
|
||||
|
||||
return a.count.CompareTo(b.count);
|
||||
}
|
||||
|
||||
/// <summary>Compare the time duration between two FrameTimes. Used for sorting in descending order</summary>
|
||||
/// <param name="a"> The first FrameTime to compare </param>
|
||||
/// <param name="b"> The second FrameTime to compare </param>
|
||||
/// <returns>-1 if a is larger, 0 if the same, 1 if a is smaller</returns>
|
||||
public static int CompareMsDescending(FrameTime a, FrameTime b)
|
||||
{
|
||||
if (a.ms == b.ms)
|
||||
{
|
||||
// secondary sort by frame index order
|
||||
return a.frameIndex.CompareTo(b.frameIndex);
|
||||
}
|
||||
|
||||
return -a.ms.CompareTo(b.ms);
|
||||
}
|
||||
|
||||
/// <summary>Compare the instance count between two FrameTimes. Used for sorting in descending order</summary>
|
||||
/// <param name="a"> The first FrameTime to compare </param>
|
||||
/// <param name="b"> The second FrameTime to compare </param>
|
||||
/// <returns>-1 if a is larger, 0 if the same, 1 if a is smaller</returns>
|
||||
public static int CompareCountDescending(FrameTime a, FrameTime b)
|
||||
{
|
||||
if (a.count == b.count)
|
||||
{
|
||||
// secondary sort by frame index order
|
||||
return a.frameIndex.CompareTo(b.frameIndex);
|
||||
}
|
||||
|
||||
return -a.count.CompareTo(b.count);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 11b7852f3babc4a938ba8e18940df7c5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 54a4b8c3a2d924a4fb740b9044db9694
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,131 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Performance.ProfileAnalyzer
|
||||
{
|
||||
internal class Histogram
|
||||
{
|
||||
Draw2D m_2D;
|
||||
Color m_ColorBarBackground;
|
||||
DisplayUnits m_Units;
|
||||
|
||||
public void SetUnits(Units units)
|
||||
{
|
||||
m_Units = new DisplayUnits(units);
|
||||
}
|
||||
|
||||
public Histogram(Draw2D draw2D, Units units)
|
||||
{
|
||||
m_2D = draw2D;
|
||||
SetUnits(units);
|
||||
m_ColorBarBackground = new Color(0.5f, 0.5f, 0.5f);
|
||||
}
|
||||
|
||||
public Histogram(Draw2D draw2D, Units units, Color barBackground)
|
||||
{
|
||||
m_2D = draw2D;
|
||||
SetUnits(units);
|
||||
m_ColorBarBackground = barBackground;
|
||||
}
|
||||
|
||||
public void DrawStart(float width)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal(GUILayout.Width(width + 10));
|
||||
|
||||
EditorGUILayout.BeginVertical();
|
||||
}
|
||||
|
||||
public void DrawEnd(float width, float min, float max, float spacing)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
float halfWidth = width / 2;
|
||||
GUIStyle leftAlignStyle = new GUIStyle(GUI.skin.label);
|
||||
leftAlignStyle.contentOffset = new Vector2(-5, 0);
|
||||
leftAlignStyle.alignment = TextAnchor.MiddleLeft;
|
||||
GUIStyle rightAlignStyle = new GUIStyle(GUI.skin.label);
|
||||
rightAlignStyle.contentOffset = new Vector2(-5, 0);
|
||||
rightAlignStyle.alignment = TextAnchor.MiddleRight;
|
||||
EditorGUILayout.LabelField(m_Units.ToString(min, false, 5, true), leftAlignStyle, GUILayout.Width(halfWidth));
|
||||
EditorGUILayout.LabelField(m_Units.ToString(max, false, 5, true), rightAlignStyle, GUILayout.Width(halfWidth));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void DrawBackground(float width, float height, int bucketCount, float min, float max, float spacing)
|
||||
{
|
||||
//bucketCount = (range == 0f) ? 1 : bucketCount;
|
||||
|
||||
float x = (spacing / 2);
|
||||
float y = 0;
|
||||
float w = ((width + spacing) / bucketCount) - spacing;
|
||||
float h = height;
|
||||
|
||||
for (int i = 0; i < bucketCount; i++)
|
||||
{
|
||||
m_2D.DrawFilledBox(x, y, w, h, m_ColorBarBackground);
|
||||
x += w;
|
||||
x += spacing;
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawData(float width, float height, int[] buckets, int totalFrameCount, float min, float max, Color barColor, float spacing)
|
||||
{
|
||||
float range = max - min;
|
||||
|
||||
//int bucketCount = (range == 0f) ? 1 : buckets.Length;
|
||||
int bucketCount = buckets.Length;
|
||||
|
||||
float x = (spacing / 2);
|
||||
float y = 0;
|
||||
float w = ((width + spacing) / bucketCount) - spacing;
|
||||
float h = height;
|
||||
|
||||
float bucketWidth = (range / bucketCount);
|
||||
Rect rect = GUILayoutUtility.GetLastRect();
|
||||
for (int bucketAt = 0; bucketAt < bucketCount; bucketAt++)
|
||||
{
|
||||
var count = buckets[bucketAt];
|
||||
|
||||
float barHeight = (h * count) / totalFrameCount;
|
||||
if (count > 0) // Make sure we always slow a small bar if non zero
|
||||
barHeight = Mathf.Max(1.0f, barHeight);
|
||||
m_2D.DrawFilledBox(x, y, w, barHeight, barColor);
|
||||
|
||||
float bucketStart = min + (bucketAt * bucketWidth);
|
||||
float bucketEnd = bucketStart + bucketWidth;
|
||||
|
||||
var tooltip = string.Format("{0}-{1}\n{2} {3}\n\nBar width: {4}",
|
||||
m_Units.ToTooltipString(bucketStart, false),
|
||||
m_Units.ToTooltipString(bucketEnd, true),
|
||||
count,
|
||||
count == 1 ? "frame" : "frames",
|
||||
m_Units.ToTooltipString(bucketWidth, true)
|
||||
);
|
||||
|
||||
var content = new GUIContent("", tooltip);
|
||||
GUI.Label(new Rect(rect.x + x, rect.y + y, w, h), content);
|
||||
|
||||
x += w;
|
||||
x += spacing;
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw(float width, float height, int[] buckets, int totalFrameCount, float min, float max, Color barColor)
|
||||
{
|
||||
DrawStart(width);
|
||||
|
||||
float spacing = 2;
|
||||
|
||||
if (m_2D.DrawStart(width, height, Draw2D.Origin.BottomLeft))
|
||||
{
|
||||
DrawBackground(width, height, buckets.Length, min, max, spacing);
|
||||
DrawData(width, height, buckets, totalFrameCount, min, max, barColor, spacing);
|
||||
m_2D.DrawEnd();
|
||||
}
|
||||
|
||||
DrawEnd(width, min, max, spacing);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dbcb296fb16194f04af7827f37fb2187
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace UnityEditor.Performance.ProfileAnalyzer
|
||||
{
|
||||
internal class MarkerColumnFilter
|
||||
{
|
||||
public enum Mode
|
||||
{
|
||||
TimeAndCount,
|
||||
Time,
|
||||
Totals,
|
||||
TimeWithTotals,
|
||||
CountTotals,
|
||||
CountPerFrame,
|
||||
Depth,
|
||||
Threads,
|
||||
Custom,
|
||||
};
|
||||
|
||||
public static readonly string[] ModeNames =
|
||||
{
|
||||
"Time and Count",
|
||||
"Time",
|
||||
"Totals",
|
||||
"Time With Totals",
|
||||
"Count Totals",
|
||||
"Count Per Frame",
|
||||
"Depths",
|
||||
"Threads",
|
||||
"Custom",
|
||||
};
|
||||
public static readonly int[] ModeValues = (int[])Enum.GetValues(typeof(Mode));
|
||||
|
||||
public Mode mode;
|
||||
public int[] visibleColumns;
|
||||
|
||||
public MarkerColumnFilter(Mode newMode)
|
||||
{
|
||||
Assert.AreEqual(ModeNames.Length, ModeValues.Length, "Number of ModeNames should match number of enum values ModeValues: You probably forgot to update one of them.");
|
||||
|
||||
mode = newMode;
|
||||
if (mode == Mode.Custom)
|
||||
mode = Mode.TimeAndCount;
|
||||
|
||||
visibleColumns = null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 814ccc2d0c490cf4b871d13ab2e4b7c3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,343 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEditor.Performance.ProfileAnalyzer
|
||||
{
|
||||
[Serializable]
|
||||
internal class MarkerData : IComparable<MarkerData>
|
||||
{
|
||||
public string name;
|
||||
public int nameLowerCaseHash; // lower case name hash for faster comparisons
|
||||
|
||||
public double msTotal; // total time of this marker on a frame
|
||||
public int count; // total number of marker calls in the timeline (multiple per frame)
|
||||
public int countMin; // min count per frame
|
||||
public int countMax; // max count per frame
|
||||
public float countMean; // mean over all frames
|
||||
public int countMedian; // median over all frames
|
||||
public int countLowerQuartile; // over all frames
|
||||
public int countUpperQuartile; // over all frames
|
||||
public float countStandardDeviation;
|
||||
public int lastFrame;
|
||||
public int presentOnFrameCount; // number of frames containing this marker
|
||||
public int firstFrameIndex;
|
||||
public float msMean; // mean over all frames
|
||||
public float msMedian; // median over all frames
|
||||
public float msLowerQuartile; // over all frames
|
||||
public float msUpperQuartile; // over all frames
|
||||
public float msMin; // min total time per frame
|
||||
public float msMax; // max total time per frame
|
||||
public float msStandardDeviation;
|
||||
public int minIndividualFrameIndex;
|
||||
public int maxIndividualFrameIndex;
|
||||
public float msMinIndividual; // min individual function call
|
||||
public float msMaxIndividual; // max individual function call
|
||||
public float msAtMedian; // time at median frame
|
||||
public int medianFrameIndex; // frame this markers median value is found on
|
||||
public int minFrameIndex;
|
||||
public int maxFrameIndex;
|
||||
public int minDepth;
|
||||
public int maxDepth;
|
||||
public List<string> threads;
|
||||
|
||||
const int bucketCount = 20;
|
||||
public int[] buckets; // Each bucket contains 'number of frames' for 'sum of markers in the frame' in that range
|
||||
public int[] countBuckets; // Each bucket contains 'number of frames' for 'count in the frame' in that range
|
||||
public List<FrameTime> frames;
|
||||
|
||||
public double timeRemoved;
|
||||
public double timeIgnored;
|
||||
|
||||
public MarkerData(string markerName)
|
||||
{
|
||||
buckets = new int[bucketCount];
|
||||
countBuckets = new int[bucketCount];
|
||||
frames = new List<FrameTime>();
|
||||
threads = new List<string>();
|
||||
|
||||
name = markerName;
|
||||
nameLowerCaseHash = markerName.ToLower().GetHashCode();
|
||||
msTotal = 0.0;
|
||||
count = 0;
|
||||
countMin = 0;
|
||||
countMax = 0;
|
||||
countMean = 0f;
|
||||
countMedian = 0;
|
||||
countLowerQuartile = 0;
|
||||
countUpperQuartile = 0;
|
||||
countStandardDeviation = 0f;
|
||||
lastFrame = -1;
|
||||
presentOnFrameCount = 0;
|
||||
firstFrameIndex = -1;
|
||||
msMean = 0f;
|
||||
msMedian = 0f;
|
||||
msLowerQuartile = 0f;
|
||||
msUpperQuartile = 0f;
|
||||
msMin = float.MaxValue;
|
||||
msMax = float.MinValue;
|
||||
msStandardDeviation = 0f;
|
||||
minIndividualFrameIndex = 0;
|
||||
maxIndividualFrameIndex = 0;
|
||||
msMinIndividual = float.MaxValue;
|
||||
msMaxIndividual = float.MinValue;
|
||||
msAtMedian = 0f;
|
||||
medianFrameIndex = 0;
|
||||
minFrameIndex = 0;
|
||||
maxFrameIndex = 0;
|
||||
minDepth = 0;
|
||||
maxDepth = 0;
|
||||
|
||||
for (int b = 0; b < buckets.Length; b++)
|
||||
{
|
||||
buckets[b] = 0;
|
||||
countBuckets[b] = 0;
|
||||
}
|
||||
|
||||
timeRemoved = 0.0;
|
||||
timeIgnored = 0.0;
|
||||
}
|
||||
|
||||
/// <summary>Compare the time duration between the marker median times. Used for sorting in descending order</summary>
|
||||
/// <param name="other"> The other MarkerData to compare </param>
|
||||
/// <returns>-1 if this is larger, 0 if the same, 1 if this is smaller</returns>
|
||||
public int CompareTo(MarkerData other)
|
||||
{
|
||||
if (msMedian == other.msMedian)
|
||||
{
|
||||
if (medianFrameIndex == other.medianFrameIndex)
|
||||
{
|
||||
// Tertiary sort by name order
|
||||
return name.CompareTo(other.name);
|
||||
}
|
||||
|
||||
// Secondary sort by frame index order
|
||||
return medianFrameIndex.CompareTo(other.medianFrameIndex);
|
||||
}
|
||||
|
||||
return -msMedian.CompareTo(other.msMedian);
|
||||
}
|
||||
|
||||
public float GetFrameMs(int frameIndex)
|
||||
{
|
||||
foreach (var frameData in frames)
|
||||
{
|
||||
if (frameData.frameIndex == frameIndex)
|
||||
return frameData.ms;
|
||||
}
|
||||
|
||||
return 0f;
|
||||
}
|
||||
|
||||
public void ComputeBuckets(float min, float max)
|
||||
{
|
||||
float first = min;
|
||||
float last = max;
|
||||
float range = last - first;
|
||||
|
||||
int maxBucketIndex = (buckets.Length - 1);
|
||||
|
||||
for (int bucketIndex = 0; bucketIndex < buckets.Length; bucketIndex++)
|
||||
{
|
||||
buckets[bucketIndex] = 0;
|
||||
}
|
||||
|
||||
float scale = range > 0 ? buckets.Length / range : 0;
|
||||
// using a for loop instead of foreach is surprisingly faster on Mono
|
||||
for (int i = 0, n = frames.Count; i < n; i++)
|
||||
{
|
||||
var frameTime = frames[i];
|
||||
var ms = frameTime.ms;
|
||||
//int frameIndex = frameTime.frameIndex;
|
||||
|
||||
int bucketIndex = (int)((ms - first) * scale);
|
||||
if (bucketIndex < 0 || bucketIndex > maxBucketIndex)
|
||||
{
|
||||
// This can happen if a single marker range is longer than the frame start end (which could occur if running on a separate thread)
|
||||
// It can also occur for the highest entry in the range (max-min/range) = 1
|
||||
// if (ms > max) // Check for the spilling case
|
||||
// Debug.Log(string.Format("Marker {0} : {1}ms exceeds range {2}-{3} on frame {4}", marker.name, ms, first, last, 1+frameIndex));
|
||||
|
||||
if (bucketIndex > maxBucketIndex)
|
||||
bucketIndex = maxBucketIndex;
|
||||
else
|
||||
bucketIndex = 0;
|
||||
}
|
||||
buckets[bucketIndex] += 1;
|
||||
}
|
||||
|
||||
if (range == 0)
|
||||
{
|
||||
// All buckets will be the same
|
||||
for (int bucketIndex = 1; bucketIndex < buckets.Length; bucketIndex++)
|
||||
{
|
||||
buckets[bucketIndex] = buckets[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ComputeCountBuckets(int min, int max)
|
||||
{
|
||||
float first = min;
|
||||
float last = max;
|
||||
float range = last - first;
|
||||
|
||||
int maxBucketIndex = (countBuckets.Length - 1);
|
||||
|
||||
for (int bucketIndex = 0; bucketIndex < countBuckets.Length; bucketIndex++)
|
||||
{
|
||||
countBuckets[bucketIndex] = 0;
|
||||
}
|
||||
|
||||
float scale = range > 0 ? countBuckets.Length / range : 0;
|
||||
// using a for loop instead of foreach is surprisingly faster on Mono
|
||||
for (int i = 0, n = frames.Count; i < n; i++)
|
||||
{
|
||||
var frameTime = frames[i];
|
||||
var count = frameTime.count;
|
||||
|
||||
int bucketIndex = (int)((count - first) * scale);
|
||||
if (bucketIndex < 0 || bucketIndex > maxBucketIndex)
|
||||
{
|
||||
if (bucketIndex > maxBucketIndex)
|
||||
bucketIndex = maxBucketIndex;
|
||||
else
|
||||
bucketIndex = 0;
|
||||
}
|
||||
countBuckets[bucketIndex] += 1;
|
||||
}
|
||||
|
||||
if (range == 0)
|
||||
{
|
||||
// All buckets will be the same
|
||||
for (int bucketIndex = 1; bucketIndex < countBuckets.Length; bucketIndex++)
|
||||
{
|
||||
countBuckets[bucketIndex] = countBuckets[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetFirstThread(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.threads[0] : "";
|
||||
}
|
||||
|
||||
public static float GetMsMax(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.msMax : 0.0f;
|
||||
}
|
||||
|
||||
public static int GetMaxFrameIndex(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.maxFrameIndex : 0;
|
||||
}
|
||||
|
||||
public static float GetMsMin(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.msMin : 0.0f;
|
||||
}
|
||||
|
||||
public static int GetMinFrameIndex(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.minFrameIndex : 0;
|
||||
}
|
||||
|
||||
public static float GetMsMedian(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.msMedian : 0.0f;
|
||||
}
|
||||
|
||||
public static int GetMedianFrameIndex(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.medianFrameIndex : 0;
|
||||
}
|
||||
|
||||
public static float GetMsUpperQuartile(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.msUpperQuartile : 0.0f;
|
||||
}
|
||||
|
||||
public static float GetMsLowerQuartile(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.msLowerQuartile : 0.0f;
|
||||
}
|
||||
|
||||
public static float GetMsMean(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.msMean : 0.0f;
|
||||
}
|
||||
|
||||
public static float GetMsMinIndividual(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.msMinIndividual : 0.0f;
|
||||
}
|
||||
|
||||
public static float GetMsMaxIndividual(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.msMaxIndividual : 0.0f;
|
||||
}
|
||||
|
||||
public static int GetPresentOnFrameCount(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.presentOnFrameCount : 0;
|
||||
}
|
||||
|
||||
public static float GetMsAtMedian(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.msAtMedian : 0.0f;
|
||||
}
|
||||
|
||||
public static int GetCountMin(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.countMin : 0;
|
||||
}
|
||||
|
||||
public static int GetCountMax(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.countMax : 0;
|
||||
}
|
||||
|
||||
public static int GetCount(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.count : 0;
|
||||
}
|
||||
|
||||
public static float GetCountMean(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.countMean : 0.0f;
|
||||
}
|
||||
|
||||
public static double GetMsTotal(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.msTotal : 0.0;
|
||||
}
|
||||
|
||||
public static int GetMinDepth(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.minDepth : 0;
|
||||
}
|
||||
|
||||
public static int GetMaxDepth(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.maxDepth : 0;
|
||||
}
|
||||
public static double GetTimeRemoved(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.timeRemoved : 0.0;
|
||||
}
|
||||
public static double GetTimeIgnored(MarkerData marker)
|
||||
{
|
||||
return marker != null ? marker.timeIgnored : 0.0;
|
||||
}
|
||||
|
||||
public bool IsFullyIgnored()
|
||||
{
|
||||
if (timeIgnored > 0.0)
|
||||
{
|
||||
if (msTotal == 0.0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7636f77e28bd3480f9e22fecae16594a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace UnityEditor.Performance.ProfileAnalyzer
|
||||
{
|
||||
[Serializable]
|
||||
internal class MarkerPairing
|
||||
{
|
||||
public string name;
|
||||
public int leftIndex;
|
||||
public int rightIndex;
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60fdacb48a6fe46529c3c01c96f7d123
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,405 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Performance.ProfileAnalyzer
|
||||
{
|
||||
[Serializable]
|
||||
internal class ProfileAnalysis
|
||||
{
|
||||
FrameSummary m_FrameSummary = new FrameSummary();
|
||||
List<MarkerData> m_Markers = new List<MarkerData>();
|
||||
List<ThreadData> m_Threads = new List<ThreadData>();
|
||||
|
||||
public ProfileAnalysis()
|
||||
{
|
||||
m_FrameSummary.first = 0;
|
||||
m_FrameSummary.last = 0;
|
||||
m_FrameSummary.count = 0;
|
||||
m_FrameSummary.msTotal = 0.0;
|
||||
m_FrameSummary.msMin = float.MaxValue;
|
||||
m_FrameSummary.msMax = 0.0f;
|
||||
m_FrameSummary.minFrameIndex = 0;
|
||||
m_FrameSummary.maxFrameIndex = 0;
|
||||
m_FrameSummary.maxMarkerDepth = 0;
|
||||
m_FrameSummary.totalMarkers = 0;
|
||||
m_FrameSummary.markerCountMax = 0;
|
||||
m_FrameSummary.markerCountMaxMean = 0.0f;
|
||||
for (int b = 0; b < m_FrameSummary.buckets.Length; b++)
|
||||
m_FrameSummary.buckets[b] = 0;
|
||||
|
||||
m_Markers.Clear();
|
||||
m_Threads.Clear();
|
||||
}
|
||||
|
||||
public void SetRange(int firstFrameIndex, int lastFrameIndex)
|
||||
{
|
||||
m_FrameSummary.first = firstFrameIndex;
|
||||
m_FrameSummary.last = lastFrameIndex;
|
||||
|
||||
// Ensure these are initialized to frame indices within the range
|
||||
m_FrameSummary.minFrameIndex = firstFrameIndex;
|
||||
// if this wasn't initialized, and all frames had 0 length, it wouldn't be set in the UpdateSummary step of the analysis and point out of range
|
||||
m_FrameSummary.maxFrameIndex = firstFrameIndex;
|
||||
}
|
||||
|
||||
public void AddMarker(MarkerData marker)
|
||||
{
|
||||
m_Markers.Add(marker);
|
||||
}
|
||||
|
||||
public void AddThread(ThreadData thread)
|
||||
{
|
||||
m_Threads.Add(thread);
|
||||
}
|
||||
|
||||
public void UpdateSummary(int frameIndex, float msFrame)
|
||||
{
|
||||
m_FrameSummary.msTotal += msFrame;
|
||||
m_FrameSummary.count += 1;
|
||||
if (msFrame < m_FrameSummary.msMin)
|
||||
{
|
||||
m_FrameSummary.msMin = msFrame;
|
||||
m_FrameSummary.minFrameIndex = frameIndex;
|
||||
}
|
||||
if (msFrame > m_FrameSummary.msMax)
|
||||
{
|
||||
m_FrameSummary.msMax = msFrame;
|
||||
m_FrameSummary.maxFrameIndex = frameIndex;
|
||||
}
|
||||
|
||||
m_FrameSummary.frames.Add(new FrameTime(frameIndex, msFrame, 1));
|
||||
}
|
||||
|
||||
FrameTime GetPercentageOffset(List<FrameTime> frames, float percent, out int outputFrameIndex)
|
||||
{
|
||||
int index = (int)((frames.Count - 1) * percent / 100);
|
||||
outputFrameIndex = frames[index].frameIndex;
|
||||
|
||||
// True median is half of the sum of the middle 2 frames for an even count. However this would be a value never recorded so we avoid that.
|
||||
return frames[index];
|
||||
}
|
||||
|
||||
float GetThreadPercentageOffset(List<ThreadFrameTime> frames, float percent, out int outputFrameIndex)
|
||||
{
|
||||
int index = (int)((frames.Count - 1) * percent / 100);
|
||||
outputFrameIndex = frames[index].frameIndex;
|
||||
|
||||
// True median is half of the sum of the middle 2 frames for an even count. However this would be a value never recorded so we avoid that.
|
||||
return frames[index].ms;
|
||||
}
|
||||
|
||||
void CalculateStandardDeviations(MarkerData marker)
|
||||
{
|
||||
if (marker.frames.Count <= 1)
|
||||
{
|
||||
marker.msStandardDeviation = 0;
|
||||
marker.countStandardDeviation = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int frameCount = marker.frames.Count;
|
||||
float msMean = marker.msMean;
|
||||
float countMean = marker.countMean;
|
||||
|
||||
double msSum = 0.0;
|
||||
double countSum = 0.0;
|
||||
for (int i = 0; i < frameCount; ++i)
|
||||
{
|
||||
float delta = (marker.frames[i].ms - msMean);
|
||||
msSum += (delta * delta);
|
||||
|
||||
delta = (marker.frames[i].count - countMean);
|
||||
countSum += (delta * delta);
|
||||
}
|
||||
|
||||
double variance = msSum / (frameCount - 1);
|
||||
marker.msStandardDeviation = (float)Math.Sqrt(variance);
|
||||
variance = countSum / (frameCount - 1);
|
||||
marker.countStandardDeviation = (float)Math.Sqrt(variance);
|
||||
}
|
||||
|
||||
public void SetupMarkers()
|
||||
{
|
||||
int countMax = 0;
|
||||
float countMaxMean = 0.0f;
|
||||
|
||||
foreach (MarkerData marker in m_Markers)
|
||||
{
|
||||
marker.msAtMedian = 0.0f;
|
||||
marker.msMin = float.MaxValue;
|
||||
marker.msMax = float.MinValue;
|
||||
marker.minFrameIndex = 0;
|
||||
marker.maxFrameIndex = 0;
|
||||
marker.countMin = int.MaxValue;
|
||||
marker.countMax = int.MinValue;
|
||||
|
||||
foreach (FrameTime frameTime in marker.frames)
|
||||
{
|
||||
var ms = frameTime.ms;
|
||||
int frameIndex = frameTime.frameIndex;
|
||||
|
||||
// Total time for marker over frame
|
||||
if (ms < marker.msMin)
|
||||
{
|
||||
marker.msMin = ms;
|
||||
marker.minFrameIndex = frameIndex;
|
||||
}
|
||||
if (ms > marker.msMax)
|
||||
{
|
||||
marker.msMax = ms;
|
||||
marker.maxFrameIndex = frameIndex;
|
||||
}
|
||||
|
||||
if (frameIndex == m_FrameSummary.medianFrameIndex)
|
||||
marker.msAtMedian = ms;
|
||||
|
||||
var count = frameTime.count;
|
||||
|
||||
// count for marker over frame
|
||||
if (count < marker.countMin)
|
||||
{
|
||||
marker.countMin = count;
|
||||
}
|
||||
if (count > marker.countMax)
|
||||
{
|
||||
marker.countMax = count;
|
||||
}
|
||||
}
|
||||
|
||||
int unusedIndex;
|
||||
|
||||
marker.msMean = marker.presentOnFrameCount > 0 ? (float)(marker.msTotal / marker.presentOnFrameCount) : 0f;
|
||||
marker.frames.Sort(FrameTime.CompareCount);
|
||||
marker.countMedian = GetPercentageOffset(marker.frames, 50, out marker.medianFrameIndex).count;
|
||||
marker.countLowerQuartile = GetPercentageOffset(marker.frames, 25, out unusedIndex).count;
|
||||
marker.countUpperQuartile = GetPercentageOffset(marker.frames, 75, out unusedIndex).count;
|
||||
|
||||
marker.countMean = marker.presentOnFrameCount > 0 ? (float)marker.count / marker.presentOnFrameCount : 0f;
|
||||
marker.frames.Sort(FrameTime.CompareMs);
|
||||
marker.msMedian = GetPercentageOffset(marker.frames, 50, out marker.medianFrameIndex).ms;
|
||||
marker.msLowerQuartile = GetPercentageOffset(marker.frames, 25, out unusedIndex).ms;
|
||||
marker.msUpperQuartile = GetPercentageOffset(marker.frames, 75, out unusedIndex).ms;
|
||||
|
||||
CalculateStandardDeviations(marker);
|
||||
|
||||
if (marker.countMax > countMax)
|
||||
countMax = marker.countMax;
|
||||
if (marker.countMean > countMaxMean)
|
||||
countMaxMean = marker.countMean;
|
||||
}
|
||||
|
||||
m_FrameSummary.markerCountMax = countMax;
|
||||
m_FrameSummary.markerCountMaxMean = countMaxMean;
|
||||
}
|
||||
|
||||
public void SetupMarkerBuckets()
|
||||
{
|
||||
// using a for loop instead of foreach is surprisingly faster on Mono
|
||||
for (int i = 0, n = m_Markers.Count; i < n; i++)
|
||||
{
|
||||
var marker = m_Markers[i];
|
||||
marker.ComputeBuckets(marker.msMin, marker.msMax);
|
||||
marker.ComputeCountBuckets(marker.countMin, marker.countMax);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetupFrameBuckets(float timeScaleMax)
|
||||
{
|
||||
float first = 0;
|
||||
float last = timeScaleMax;
|
||||
float range = last - first;
|
||||
|
||||
int maxBucketIndex = m_FrameSummary.buckets.Length - 1;
|
||||
|
||||
for (int bucketIndex = 0; bucketIndex < m_FrameSummary.buckets.Length; bucketIndex++)
|
||||
{
|
||||
m_FrameSummary.buckets[bucketIndex] = 0;
|
||||
}
|
||||
|
||||
float scale = range > 0 ? m_FrameSummary.buckets.Length / range : 0;
|
||||
// using a for loop instead of foreach is surprisingly faster on Mono
|
||||
for (int i = 0, n = m_FrameSummary.frames.Count; i < n; i++)
|
||||
{
|
||||
var frameData = m_FrameSummary.frames[i];
|
||||
var msFrame = frameData.ms;
|
||||
//var frameIndex = frameData.frameIndex;
|
||||
|
||||
int bucketIndex = (int)((msFrame - first) * scale);
|
||||
if (bucketIndex < 0 || bucketIndex > maxBucketIndex)
|
||||
{
|
||||
// It can occur for the highest entry in the range (max-min/range) = 1
|
||||
// if (ms > max) // Check for the spilling case
|
||||
// Debug.Log(string.Format("Frame {0}ms exceeds range {1}-{2} on frame {3}", msFrame, first, last, frameIndex));
|
||||
if (bucketIndex > maxBucketIndex)
|
||||
bucketIndex = maxBucketIndex;
|
||||
else
|
||||
bucketIndex = 0;
|
||||
}
|
||||
m_FrameSummary.buckets[bucketIndex] += 1;
|
||||
}
|
||||
|
||||
if (range == 0)
|
||||
{
|
||||
// All buckets will be the same
|
||||
for (int bucketIndex = 1; bucketIndex < m_FrameSummary.buckets.Length; bucketIndex++)
|
||||
{
|
||||
m_FrameSummary.buckets[bucketIndex] = m_FrameSummary.buckets[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CalculateThreadMedians()
|
||||
{
|
||||
foreach (var thread in m_Threads)
|
||||
{
|
||||
if (thread.frames.Count > 0)
|
||||
{
|
||||
thread.frames.Sort();
|
||||
int unusedIndex;
|
||||
|
||||
thread.msMin = GetThreadPercentageOffset(thread.frames, 0, out thread.minFrameIndex);
|
||||
thread.msLowerQuartile = GetThreadPercentageOffset(thread.frames, 25, out unusedIndex);
|
||||
thread.msMedian = GetThreadPercentageOffset(thread.frames, 50, out thread.medianFrameIndex);
|
||||
thread.msUpperQuartile = GetThreadPercentageOffset(thread.frames, 75, out unusedIndex);
|
||||
thread.msMax = GetThreadPercentageOffset(thread.frames, 100, out thread.maxFrameIndex);
|
||||
|
||||
// Put back in order of frames
|
||||
thread.frames.Sort((a, b) => a.frameIndex.CompareTo(b.frameIndex));
|
||||
}
|
||||
else
|
||||
{
|
||||
thread.msMin = 0f;
|
||||
thread.msLowerQuartile = 0f;
|
||||
thread.msMedian = 0f;
|
||||
thread.msUpperQuartile = 0f;
|
||||
thread.msMax = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Finalise(float timeScaleMax, int maxMarkerDepth)
|
||||
{
|
||||
if (m_FrameSummary.frames.Count > 0)
|
||||
{
|
||||
m_FrameSummary.frames.Sort();
|
||||
m_FrameSummary.msMean = (float)(m_FrameSummary.msTotal / m_FrameSummary.count);
|
||||
m_FrameSummary.msMedian = GetPercentageOffset(m_FrameSummary.frames, 50, out m_FrameSummary.medianFrameIndex).ms;
|
||||
int unusedIndex;
|
||||
m_FrameSummary.msLowerQuartile = GetPercentageOffset(m_FrameSummary.frames, 25, out unusedIndex).ms;
|
||||
m_FrameSummary.msUpperQuartile = GetPercentageOffset(m_FrameSummary.frames, 75, out unusedIndex).ms;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_FrameSummary.msMean = 0f;
|
||||
m_FrameSummary.msMedian = 0f;
|
||||
m_FrameSummary.msLowerQuartile = 0f;
|
||||
m_FrameSummary.msUpperQuartile = 0f;
|
||||
|
||||
// This started as float.MaxValue and won't have been updated
|
||||
m_FrameSummary.msMin = 0f;
|
||||
}
|
||||
// No longer need the frame time list ?
|
||||
//m_frameSummary.msFrame.Clear();
|
||||
m_FrameSummary.maxMarkerDepth = maxMarkerDepth;
|
||||
|
||||
if (timeScaleMax <= 0.0f)
|
||||
{
|
||||
// If max frame time range not specified then use the max frame value found.
|
||||
timeScaleMax = m_FrameSummary.msMax;
|
||||
}
|
||||
else if (timeScaleMax < m_FrameSummary.msMax)
|
||||
{
|
||||
Debug.Log(string.Format("Expanding timeScaleMax {0} to match max value found {1}", timeScaleMax, m_FrameSummary.msMax));
|
||||
|
||||
// If max frame time range too small we must expand it.
|
||||
timeScaleMax = m_FrameSummary.msMax;
|
||||
}
|
||||
|
||||
SetupMarkers();
|
||||
SetupMarkerBuckets();
|
||||
SetupFrameBuckets(timeScaleMax);
|
||||
|
||||
// Sort in median order (highest first)
|
||||
m_Markers.Sort(SortByAtMedian);
|
||||
|
||||
CalculateThreadMedians();
|
||||
}
|
||||
|
||||
int SortByAtMedian(MarkerData a, MarkerData b)
|
||||
{
|
||||
if (a.msAtMedian == b.msAtMedian)
|
||||
return -a.medianFrameIndex.CompareTo(b.medianFrameIndex);
|
||||
|
||||
return -a.msAtMedian.CompareTo(b.msAtMedian);
|
||||
}
|
||||
|
||||
public List<MarkerData> GetMarkers()
|
||||
{
|
||||
return m_Markers;
|
||||
}
|
||||
|
||||
public List<ThreadData> GetThreads()
|
||||
{
|
||||
return m_Threads;
|
||||
}
|
||||
|
||||
public ThreadData GetThreadByName(string threadNameWithIndex)
|
||||
{
|
||||
foreach (var thread in m_Threads)
|
||||
{
|
||||
if (thread.threadNameWithIndex == threadNameWithIndex)
|
||||
return thread;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public FrameSummary GetFrameSummary()
|
||||
{
|
||||
return m_FrameSummary;
|
||||
}
|
||||
|
||||
public MarkerData GetMarker(int index)
|
||||
{
|
||||
if (index < 0 || index >= m_Markers.Count)
|
||||
return null;
|
||||
|
||||
return m_Markers[index];
|
||||
}
|
||||
|
||||
public int GetMarkerIndexByName(string markerName)
|
||||
{
|
||||
if (markerName == null)
|
||||
return -1;
|
||||
|
||||
for (int index = 0; index < m_Markers.Count; index++)
|
||||
{
|
||||
var marker = m_Markers[index];
|
||||
if (marker.name == markerName)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public MarkerData GetMarkerByName(string markerName)
|
||||
{
|
||||
if (markerName == null)
|
||||
return null;
|
||||
|
||||
for (int index = 0; index < m_Markers.Count; index++)
|
||||
{
|
||||
var marker = m_Markers[index];
|
||||
if (marker.name == markerName)
|
||||
{
|
||||
return marker;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7cee1025e74448acbbb8bf2b82d9bfc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 317d76fd107c444c7822b9c99d48bd30
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,281 @@
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
namespace UnityEditor.Performance.ProfileAnalyzer
|
||||
{
|
||||
internal class ProfileAnalyzerExportWindow : EditorWindow
|
||||
{
|
||||
internal static class Styles
|
||||
{
|
||||
public static readonly GUIContent markerTable = new GUIContent("Marker table", "Export data from the single view marker table");
|
||||
public static readonly GUIContent singleFrameTimes = new GUIContent("Single Frame Times", "Export frame time data from the single view");
|
||||
public static readonly GUIContent comparisonTables = new GUIContent("Comparison table", "Export data from the comparsion view marker table");
|
||||
public static readonly GUIContent comparisonFrameTimes = new GUIContent("Comparison Frame Times", "Export frame time data from the comparison view");
|
||||
}
|
||||
|
||||
ProfileAnalyzerWindow m_ProfileAnalyzerWindow;
|
||||
|
||||
ProfileDataView m_ProfileDataView;
|
||||
ProfileDataView m_LeftDataView;
|
||||
ProfileDataView m_RightDataView;
|
||||
|
||||
static public ProfileAnalyzerExportWindow FindOpenWindow()
|
||||
{
|
||||
UnityEngine.Object[] windows = Resources.FindObjectsOfTypeAll(typeof(ProfileAnalyzerExportWindow));
|
||||
if (windows != null && windows.Length > 0)
|
||||
return windows[0] as ProfileAnalyzerExportWindow;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static public bool IsOpen()
|
||||
{
|
||||
if (FindOpenWindow() != null)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static public ProfileAnalyzerExportWindow Open(float screenX, float screenY, ProfileDataView profileSingleView, ProfileDataView profileLeftView, ProfileDataView profileRightView, ProfileAnalyzerWindow profileAnalyzerWindow)
|
||||
{
|
||||
ProfileAnalyzerExportWindow window = GetWindow<ProfileAnalyzerExportWindow>("Export");
|
||||
window.minSize = new Vector2(200, 180);
|
||||
window.position = new Rect(screenX, screenY, 200, 180);
|
||||
window.m_ProfileAnalyzerWindow = profileAnalyzerWindow;
|
||||
window.SetData(profileSingleView, profileLeftView, profileRightView);
|
||||
window.Show();
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
static public void CloseAll()
|
||||
{
|
||||
ProfileAnalyzerExportWindow window = GetWindow<ProfileAnalyzerExportWindow>("Export");
|
||||
window.Close();
|
||||
}
|
||||
|
||||
public void SetData(ProfileDataView profileDataView, ProfileDataView leftDataView, ProfileDataView rightDataView)
|
||||
{
|
||||
m_ProfileDataView = profileDataView;
|
||||
m_LeftDataView = leftDataView;
|
||||
m_RightDataView = rightDataView;
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
EditorGUILayout.BeginVertical(GUILayout.ExpandWidth(true));
|
||||
GUILayout.Label("Export as CSV:");
|
||||
GUILayout.Label("");
|
||||
|
||||
GUILayout.Label("Single View");
|
||||
|
||||
bool enabled = GUI.enabled;
|
||||
if (m_ProfileDataView == null || !m_ProfileDataView.IsDataValid())
|
||||
GUI.enabled = false;
|
||||
if (GUILayout.Button(Styles.markerTable))
|
||||
SaveMarkerTableCSV();
|
||||
GUI.enabled = enabled;
|
||||
|
||||
if (m_ProfileDataView == null || m_ProfileDataView.analysis == null)
|
||||
GUI.enabled = false;
|
||||
if (GUILayout.Button(Styles.singleFrameTimes))
|
||||
SaveFrameTimesCSV();
|
||||
GUI.enabled = enabled;
|
||||
|
||||
GUILayout.Label("Comparison View");
|
||||
|
||||
if (!m_ProfileAnalyzerWindow.CanExportComparisonTable())
|
||||
GUI.enabled = false;
|
||||
if (GUILayout.Button(Styles.comparisonTables))
|
||||
SaveComparisonTableCSV();
|
||||
GUI.enabled = enabled;
|
||||
if (m_LeftDataView == null || !m_LeftDataView.IsDataValid() || m_RightDataView == null || !m_RightDataView.IsDataValid())
|
||||
GUI.enabled = false;
|
||||
if (GUILayout.Button(Styles.comparisonFrameTimes))
|
||||
SaveComparisonFrameTimesCSV();
|
||||
GUI.enabled = enabled;
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
void SaveMarkerTableCSV()
|
||||
{
|
||||
if (m_ProfileDataView.analysis == null)
|
||||
return;
|
||||
|
||||
string path = EditorUtility.SaveFilePanel("Save marker table CSV data", "", "markerTable.csv", "csv");
|
||||
if (path.Length != 0)
|
||||
{
|
||||
var analytic = ProfileAnalyzerAnalytics.BeginAnalytic();
|
||||
using (StreamWriter file = new StreamWriter(path))
|
||||
{
|
||||
file.Write("Name; ");
|
||||
file.Write("Median Time; Min Time; Max Time; ");
|
||||
file.Write("Median Frame Index; Min Frame Index; Max Frame Index; ");
|
||||
file.Write("Min Depth; Max Depth; ");
|
||||
file.Write("Total Time; ");
|
||||
file.Write("Mean Time; Time Lower Quartile; Time Upper Quartile; ");
|
||||
file.Write("Count Total; Count Median; Count Min; Count Max; ");
|
||||
file.Write("Number of frames containing Marker; ");
|
||||
file.Write("First Frame Index; ");
|
||||
file.Write("Time Min Individual; Time Max Individual; ");
|
||||
file.Write("Min Individual Frame; Max Individual Frame; ");
|
||||
file.WriteLine("Time at Median Frame");
|
||||
|
||||
List<MarkerData> markerData = m_ProfileDataView.analysis.GetMarkers();
|
||||
markerData.Sort();
|
||||
foreach (MarkerData marker in markerData)
|
||||
{
|
||||
var markerName = marker.name;
|
||||
if (markerName.IndexOf('\"') >= 0)
|
||||
// replace all double quotation marks with single ones to avoid this breaking the escaping with double quotation marks
|
||||
markerName = markerName.Replace('\"', '\'');
|
||||
|
||||
int medianFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(marker.medianFrameIndex, m_ProfileDataView);
|
||||
int minFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(marker.minFrameIndex, m_ProfileDataView);
|
||||
int maxFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(marker.maxFrameIndex, m_ProfileDataView);
|
||||
int firstFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(marker.firstFrameIndex, m_ProfileDataView);
|
||||
int minIndividualFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(marker.minIndividualFrameIndex, m_ProfileDataView);
|
||||
int maxIndividualFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(marker.maxIndividualFrameIndex, m_ProfileDataView);
|
||||
|
||||
// "Escape" marker names in case it has commas in it.
|
||||
file.Write("\"{0}\";", markerName);
|
||||
file.Write(string.Format(CultureInfo.InvariantCulture,"{0};{1};{2};",
|
||||
marker.msMedian, marker.msMin, marker.msMax));
|
||||
file.Write("{0};{1};{2};",
|
||||
medianFrameIndex, minFrameIndex, maxFrameIndex);
|
||||
file.Write("{0};{1};",
|
||||
marker.minDepth, marker.maxDepth);
|
||||
file.Write(string.Format(CultureInfo.InvariantCulture, "{0};",
|
||||
marker.msTotal));
|
||||
file.Write(string.Format(CultureInfo.InvariantCulture, "{0};{1};{2};",
|
||||
marker.msMean, marker.msLowerQuartile, marker.msUpperQuartile));
|
||||
file.Write("{0};{1};{2};{3};",
|
||||
marker.count, marker.countMedian, marker.countMin, marker.countMax);
|
||||
file.Write("{0};", marker.presentOnFrameCount);
|
||||
file.Write("{0};", firstFrameIndex);
|
||||
file.Write(string.Format(CultureInfo.InvariantCulture, "{0};{1};",
|
||||
marker.msMinIndividual, marker.msMaxIndividual));
|
||||
file.Write("{0};{1};",
|
||||
minIndividualFrameIndex, maxIndividualFrameIndex);
|
||||
file.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0}", marker.msAtMedian));
|
||||
}
|
||||
}
|
||||
ProfileAnalyzerAnalytics.SendUIButtonEvent(ProfileAnalyzerAnalytics.UIButton.ExportSingleFrames, analytic);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveFrameTimesCSV()
|
||||
{
|
||||
if (m_ProfileDataView == null)
|
||||
return;
|
||||
if (!m_ProfileDataView.IsDataValid())
|
||||
return;
|
||||
|
||||
string path = EditorUtility.SaveFilePanel("Save frame time CSV data", "", "frameTime.csv", "csv");
|
||||
if (path.Length != 0)
|
||||
{
|
||||
var analytic = ProfileAnalyzerAnalytics.BeginAnalytic();
|
||||
using (StreamWriter file = new StreamWriter(path))
|
||||
{
|
||||
file.WriteLine("Frame Offset; Frame Index; Frame Time (ms); Time from first frame (ms)");
|
||||
float maxFrames = m_ProfileDataView.data.GetFrameCount();
|
||||
|
||||
var frame = m_ProfileDataView.data.GetFrame(0);
|
||||
// msStartTime isn't very accurate so we don't use it
|
||||
|
||||
double msTimePassed = 0.0;
|
||||
for (int frameOffset = 0; frameOffset < maxFrames; frameOffset++)
|
||||
{
|
||||
frame = m_ProfileDataView.data.GetFrame(frameOffset);
|
||||
int frameIndex = m_ProfileDataView.data.OffsetToDisplayFrame(frameOffset);
|
||||
frameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(frameIndex, m_ProfileDataView);
|
||||
|
||||
float msFrame = frame.msFrame;
|
||||
file.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0};{1};{2};{3}",
|
||||
frameOffset, frameIndex, msFrame, msTimePassed));
|
||||
|
||||
msTimePassed += msFrame;
|
||||
}
|
||||
}
|
||||
ProfileAnalyzerAnalytics.SendUIButtonEvent(ProfileAnalyzerAnalytics.UIButton.ExportSingleFrames, analytic);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveComparisonFrameTimesCSV()
|
||||
{
|
||||
if (m_LeftDataView == null || m_RightDataView == null)
|
||||
return;
|
||||
if (!m_LeftDataView.IsDataValid() || !m_RightDataView.IsDataValid())
|
||||
return;
|
||||
|
||||
string path = EditorUtility.SaveFilePanel("Save comparison frame time CSV data", "", "frameTimeComparison.csv", "csv");
|
||||
if (path.Length != 0)
|
||||
{
|
||||
var analytic = ProfileAnalyzerAnalytics.BeginAnalytic();
|
||||
using (StreamWriter file = new StreamWriter(path))
|
||||
{
|
||||
file.Write("Frame Offset; ");
|
||||
file.Write("Left Frame Index; Right Frame Index; ");
|
||||
file.Write("Left Frame Time (ms); Left time from first frame (ms); ");
|
||||
file.Write("Right Frame Time (ms); Right time from first frame (ms); ");
|
||||
file.WriteLine("Frame Time Diff (ms)");
|
||||
float maxFrames = Math.Max(m_LeftDataView.data.GetFrameCount(), m_RightDataView.data.GetFrameCount());
|
||||
|
||||
var leftFrame = m_LeftDataView.data.GetFrame(0);
|
||||
var rightFrame = m_RightDataView.data.GetFrame(0);
|
||||
|
||||
// msStartTime isn't very accurate so we don't use it
|
||||
|
||||
double msTimePassedLeft = 0.0;
|
||||
double msTimePassedRight = 0.0;
|
||||
|
||||
for (int frameOffset = 0; frameOffset < maxFrames; frameOffset++)
|
||||
{
|
||||
leftFrame = m_LeftDataView.data.GetFrame(frameOffset);
|
||||
rightFrame = m_RightDataView.data.GetFrame(frameOffset);
|
||||
int leftFrameIndex = m_LeftDataView.data.OffsetToDisplayFrame(frameOffset);
|
||||
leftFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(leftFrameIndex, m_LeftDataView);
|
||||
int rightFrameIndex = m_RightDataView.data.OffsetToDisplayFrame(frameOffset);
|
||||
rightFrameIndex = m_ProfileAnalyzerWindow.GetRemappedUIFrameIndex(rightFrameIndex, m_RightDataView);
|
||||
|
||||
float msFrameLeft = leftFrame != null ? leftFrame.msFrame : 0;
|
||||
float msFrameRight = rightFrame != null ? rightFrame.msFrame : 0;
|
||||
float msFrameDiff = msFrameRight - msFrameLeft;
|
||||
file.Write("{0};", frameOffset);
|
||||
file.Write("{0};{1};", leftFrameIndex, rightFrameIndex);
|
||||
file.Write(string.Format(CultureInfo.InvariantCulture, "{0};{1};", msFrameLeft, msTimePassedLeft));
|
||||
file.Write(string.Format(CultureInfo.InvariantCulture, "{0};{1};", msFrameRight, msTimePassedRight));
|
||||
file.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0}", msFrameDiff));
|
||||
|
||||
msTimePassedLeft += msFrameLeft;
|
||||
msTimePassedRight += msFrameRight;
|
||||
}
|
||||
}
|
||||
ProfileAnalyzerAnalytics.SendUIButtonEvent(ProfileAnalyzerAnalytics.UIButton.ExportComparisonFrames, analytic);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveComparisonTableCSV()
|
||||
{
|
||||
if (m_LeftDataView == null || m_RightDataView == null)
|
||||
return;
|
||||
if (!m_LeftDataView.IsDataValid() || !m_RightDataView.IsDataValid())
|
||||
return;
|
||||
|
||||
string path = EditorUtility.SaveFilePanel("Save comparison table CSV data", "", "tableComparison.csv", "csv");
|
||||
if (path.Length != 0)
|
||||
{
|
||||
var analytic = ProfileAnalyzerAnalytics.BeginAnalytic();
|
||||
using (StreamWriter file = new StreamWriter(path))
|
||||
{
|
||||
m_ProfileAnalyzerWindow.TryExportComparisonTable(file);
|
||||
}
|
||||
ProfileAnalyzerAnalytics.SendUIButtonEvent(ProfileAnalyzerAnalytics.UIButton.ExportComparisonFrames, analytic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ccd88eea7c8284ac18aff2e257aeb84a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,106 @@
|
||||
Shader "Unlit/ProfileAnalyzerShader"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_StencilComp ("Stencil Comparison", Float) = 8
|
||||
_Stencil ("Stencil ID", Float) = 0
|
||||
_StencilOp ("Stencil Operation", Float) = 0
|
||||
_StencilWriteMask ("Stencil Write Mask", Float) = 255
|
||||
_StencilReadMask ("Stencil Read Mask", Float) = 255
|
||||
|
||||
_ColorMask ("Color Mask", Float) = 15
|
||||
|
||||
[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
|
||||
|
||||
_ClipRect ("Clip Rect", vector) = (-32767, -32767, 32767, 32767)
|
||||
}
|
||||
|
||||
SubShader
|
||||
{
|
||||
Tags
|
||||
{
|
||||
"Queue"="Transparent"
|
||||
"IgnoreProjector"="True"
|
||||
"RenderType"="Transparent"
|
||||
"PreviewType"="Plane"
|
||||
"CanUseSpriteAtlas"="True"
|
||||
}
|
||||
|
||||
Stencil
|
||||
{
|
||||
Ref [_Stencil]
|
||||
Comp [_StencilComp]
|
||||
Pass [_StencilOp]
|
||||
ReadMask [_StencilReadMask]
|
||||
WriteMask [_StencilWriteMask]
|
||||
}
|
||||
|
||||
//Tags { "RenderType"="Transparent" }
|
||||
LOD 100
|
||||
|
||||
//ZWrite Off
|
||||
//Blend SrcAlpha OneMinusSrcAlpha
|
||||
|
||||
Cull Off
|
||||
Lighting Off
|
||||
ZWrite Off
|
||||
ZTest [unity_GUIZTestMode]
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
ColorMask [_ColorMask]
|
||||
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
#include "UnityUI.cginc"
|
||||
|
||||
#pragma multi_compile _ UNITY_UI_ALPHACLIP
|
||||
|
||||
struct appdata
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
fixed4 color : COLOR;
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float4 vertex : SV_POSITION;
|
||||
fixed4 color : COLOR;
|
||||
float4 worldPosition : TEXCOORD1;
|
||||
};
|
||||
|
||||
bool _UseClipRect;
|
||||
float4 _ClipRect;
|
||||
|
||||
v2f vert (appdata v)
|
||||
{
|
||||
v2f o;
|
||||
o.worldPosition = v.vertex;
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
o.color.rgba = v.color;
|
||||
return o;
|
||||
}
|
||||
|
||||
//fixed4 frag (v2f i) : SV_Target { return i.color; }
|
||||
|
||||
fixed4 frag (v2f i) : SV_Target
|
||||
{
|
||||
half4 color = i.color;
|
||||
|
||||
if (_UseClipRect)
|
||||
color.a *= UnityGet2DClipping(i.worldPosition.xy, _ClipRect);
|
||||
|
||||
#ifdef UNITY_UI_ALPHACLIP
|
||||
clip (color.a - 0.001);
|
||||
#endif
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 493b79ea9c9be44ed8b702014d3ac49c
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0dc59854f72ef4a1fb6dbb8d0cd6aea3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5cea2082789f54c25b65fd1fef416863
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,172 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEditor.Performance.ProfileAnalyzer
|
||||
{
|
||||
[Serializable]
|
||||
internal class ProfileDataView
|
||||
{
|
||||
public string path;
|
||||
public ProfileData data;
|
||||
public ProfileAnalysis analysisFullNew;
|
||||
public ProfileAnalysis analysisFull;
|
||||
public ProfileAnalysis analysisNew;
|
||||
public ProfileAnalysis analysis;
|
||||
public List<int> selectedIndices = new List<int> { 0, 0 };
|
||||
[NonSerialized]
|
||||
public bool inSyncWithProfilerData;
|
||||
public bool containsWaitForFPS { get; private set; }
|
||||
public bool containsWaitForPresent { get; private set; }
|
||||
|
||||
public ProfileDataView()
|
||||
{
|
||||
}
|
||||
|
||||
public ProfileDataView(ProfileDataView dataView)
|
||||
{
|
||||
path = dataView.path;
|
||||
data = dataView.data;
|
||||
analysisFullNew = dataView.analysisFullNew;
|
||||
analysisFull = dataView.analysisFull;
|
||||
analysisNew = dataView.analysisNew;
|
||||
analysis = dataView.analysis;
|
||||
selectedIndices = new List<int>(dataView.selectedIndices);
|
||||
inSyncWithProfilerData = dataView.inSyncWithProfilerData;
|
||||
containsWaitForFPS = dataView.containsWaitForFPS;
|
||||
containsWaitForPresent = dataView.containsWaitForPresent;
|
||||
}
|
||||
|
||||
public void FindKeyMarkers()
|
||||
{
|
||||
containsWaitForFPS = data.GetMarkerIndex("WaitForTargetFPS") != -1;
|
||||
containsWaitForPresent = data.GetMarkerIndex("Gfx.WaitForPresentOnGfxThread") != -1;
|
||||
}
|
||||
|
||||
public bool IsDataValid()
|
||||
{
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
if (data.GetFrameCount() == 0)
|
||||
return false;
|
||||
|
||||
if (data.NeedsMarkerRebuild)
|
||||
{
|
||||
if (!ProfileData.Load(data.FilePath, out data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool HasValidSelection()
|
||||
{
|
||||
if (selectedIndices.Count == 2 && selectedIndices[0] == 0 && selectedIndices[1] == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool HasSelection()
|
||||
{
|
||||
if (selectedIndices.Count == 0)
|
||||
return false;
|
||||
if (selectedIndices.Count == data.GetFrameCount())
|
||||
return false;
|
||||
|
||||
return HasValidSelection();
|
||||
}
|
||||
|
||||
public bool AllSelected()
|
||||
{
|
||||
if (selectedIndices.Count != data.GetFrameCount())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int GetMaxDepth()
|
||||
{
|
||||
return (analysis == null) ? 1 : analysis.GetFrameSummary().maxMarkerDepth;
|
||||
}
|
||||
|
||||
int Clamp(int value, int min, int max)
|
||||
{
|
||||
if (value < min)
|
||||
value = min;
|
||||
else if (value > max)
|
||||
value = max;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public int ClampToValidDepthValue(int depthFilter)
|
||||
{
|
||||
// ProfileAnalyzer.kDepthAll is special case that we don't test for here
|
||||
|
||||
// If we have no depth values then return -1 for all (as clamp expects min<max)
|
||||
int maxDepth = GetMaxDepth();
|
||||
if (maxDepth < 1)
|
||||
return ProfileAnalyzer.kDepthAll;
|
||||
|
||||
return Clamp(depthFilter, 1, maxDepth);
|
||||
}
|
||||
|
||||
bool SelectAllFramesContainingMarker(string markerName, ProfileAnalysis inAnalysis)
|
||||
{
|
||||
if (inAnalysis == null)
|
||||
return false;
|
||||
|
||||
selectedIndices.Clear();
|
||||
|
||||
MarkerData markerData = inAnalysis.GetMarkerByName(markerName);
|
||||
if (markerData == null)
|
||||
return true;
|
||||
|
||||
foreach (var frameTime in markerData.frames)
|
||||
{
|
||||
selectedIndices.Add(frameTime.frameIndex);
|
||||
}
|
||||
|
||||
// Order from lowest to highest so the start/end frame display makes sense
|
||||
selectedIndices.Sort();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SelectAllFramesContainingMarker(string markerName, bool inSelection)
|
||||
{
|
||||
return SelectAllFramesContainingMarker(markerName, inSelection ? analysis : analysisFull);
|
||||
}
|
||||
|
||||
int ClampToRange(int value, int min, int max)
|
||||
{
|
||||
if (value < min)
|
||||
value = min;
|
||||
if (value > max)
|
||||
value = max;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public void ClearSelection()
|
||||
{
|
||||
selectedIndices.Clear();
|
||||
}
|
||||
|
||||
public void SelectFullRange()
|
||||
{
|
||||
selectedIndices.Clear();
|
||||
|
||||
if (data == null)
|
||||
return;
|
||||
|
||||
for (int offset = 0; offset < data.GetFrameCount(); offset++)
|
||||
{
|
||||
selectedIndices.Add(data.OffsetToDisplayFrame(offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59e8a7346ec034a4387b6ca1ab20b83e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 981ca102f47f145c1977153854cce718
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8e7ffaacab264ab6ba5aa70f432785f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,36 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Performance.ProfileAnalyzer
|
||||
{
|
||||
internal class ProgressBarDisplay
|
||||
{
|
||||
int m_TotalFrames;
|
||||
int m_CurrentFrame;
|
||||
string m_Title;
|
||||
string m_Description;
|
||||
|
||||
public void InitProgressBar(string title, string description, int frames)
|
||||
{
|
||||
m_CurrentFrame = 0;
|
||||
m_TotalFrames = frames;
|
||||
|
||||
m_Title = title;
|
||||
m_Description = description;
|
||||
|
||||
EditorUtility.DisplayProgressBar(m_Title, m_Description, m_CurrentFrame);
|
||||
}
|
||||
|
||||
public void AdvanceProgressBar()
|
||||
{
|
||||
m_CurrentFrame++;
|
||||
int currentFrame = Mathf.Clamp(0, m_CurrentFrame, m_TotalFrames);
|
||||
float progress = m_TotalFrames > 0 ? (float)currentFrame / m_TotalFrames : 0f;
|
||||
EditorUtility.DisplayProgressBar(m_Title, m_Description, progress);
|
||||
}
|
||||
|
||||
public void ClearProgressBar()
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c27dfe7bd1055403b9dac63caf69c135
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user