-
Notifications
You must be signed in to change notification settings - Fork 855
Realtime profiler (HDRP & URP) #5419
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8989e11
5cd4cfa
2223ee2
57a2a3c
7d61278
0bcdd02
4b2f967
d667a8b
e15c2c8
246c150
9a4a208
8df1dde
48e3fed
892b711
5276e95
851c3e2
758d800
b90d84f
f165eae
0697812
03dc0e9
bf62e35
028c51a
c0d93a3
c916aae
f8f1f31
753f853
5c1b346
1933e07
74f2444
6839ab6
93b073f
1ec6257
0e19d9d
a054440
28505ca
79599e6
2515758
8fc32d8
ddc3d21
3983c0e
3d0ef52
5e4f2dd
9bea634
a88be08
f9e7daf
ad106af
1be2ac6
b9fe1c2
6b998bd
dd1ce26
83a4e46
98aa73f
dbedc16
84d4ca6
c29d651
9afdf0f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using UnityEngine; | ||
|
||
//#define RTPROFILER_DEBUG | ||
|
||
namespace UnityEngine.Rendering | ||
{ | ||
public class DebugFrameTiming | ||
{ | ||
const string k_FpsFormatString = "{0:F1}"; | ||
const string k_MsFormatString = "{0:F2}ms"; | ||
const float k_RefreshRate = 1f / 5f; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why this value for the refresh rate? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's the same value that HDRP had previously, so I didn't change it. I guess the refresh rate is a compromise between performance (it costs something to update the value), readability (too quickly changing values can be hard to read) and correctness (how up to date the value is). I think this value is a reasonable compromise. |
||
|
||
internal FrameTimeSampleHistory m_FrameHistory = new(); | ||
internal BottleneckHistory m_BottleneckHistory = new(); | ||
|
||
/// <summary> | ||
/// Size of the Bottleneck History Window in number of samples. | ||
/// </summary> | ||
public int bottleneckHistorySize { get; set; } = 60; | ||
|
||
/// <summary> | ||
/// Size of the Sample History Window in number of samples. | ||
/// </summary> | ||
public int sampleHistorySize { get; set; } = 30; | ||
|
||
FrameTiming[] m_Timing = new FrameTiming[1]; | ||
FrameTimeSample m_Sample = new FrameTimeSample(); | ||
|
||
/// <summary> | ||
/// Update timing data from profiling counters. | ||
/// </summary> | ||
public void UpdateFrameTiming() | ||
{ | ||
m_Timing[0] = default; | ||
m_Sample = default; | ||
FrameTimingManager.CaptureFrameTimings(); | ||
FrameTimingManager.GetLatestTimings(1, m_Timing); | ||
|
||
if (m_Timing.Length > 0) | ||
{ | ||
m_Sample.FullFrameTime = (float)m_Timing.First().cpuFrameTime; | ||
m_Sample.FramesPerSecond = m_Sample.FullFrameTime > 0f ? 1000f / m_Sample.FullFrameTime : 0f; | ||
m_Sample.MainThreadCPUFrameTime = (float)m_Timing.First().cpuMainThreadFrameTime; | ||
m_Sample.MainThreadCPUPresentWaitTime = (float)m_Timing.First().cpuMainThreadPresentWaitTime; | ||
m_Sample.RenderThreadCPUFrameTime = (float)m_Timing.First().cpuRenderThreadFrameTime; | ||
m_Sample.GPUFrameTime = (float)m_Timing.First().gpuFrameTime; | ||
} | ||
|
||
m_FrameHistory.DiscardOldSamples(sampleHistorySize); | ||
m_FrameHistory.Add(m_Sample); | ||
m_FrameHistory.ComputeAggregateValues(); | ||
|
||
m_BottleneckHistory.DiscardOldSamples(bottleneckHistorySize); | ||
m_BottleneckHistory.AddBottleneckFromAveragedSample(m_FrameHistory.SampleAverage); | ||
m_BottleneckHistory.ComputeHistogram(); | ||
} | ||
|
||
/// <summary> | ||
/// Add frame timing data widgets to debug UI. | ||
/// </summary> | ||
/// <param name="list">List of widgets to add the stats.</param> | ||
public void RegisterDebugUI(List<DebugUI.Widget> list) | ||
{ | ||
list.Add(new DebugUI.Foldout() | ||
{ | ||
displayName = "Frame Stats", | ||
opened = true, | ||
columnLabels = new string[] { "Avg", "Min", "Max" }, | ||
children = | ||
{ | ||
new DebugUI.ValueTuple | ||
{ | ||
displayName = "Frame Rate (FPS)", | ||
values = new[] | ||
{ | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_FpsFormatString, getter = () => m_FrameHistory.SampleAverage.FramesPerSecond }, | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_FpsFormatString, getter = () => m_FrameHistory.SampleMin.FramesPerSecond }, | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_FpsFormatString, getter = () => m_FrameHistory.SampleMax.FramesPerSecond }, | ||
} | ||
}, | ||
new DebugUI.ValueTuple | ||
{ | ||
displayName = "Frame Time", | ||
values = new[] | ||
{ | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleAverage.FullFrameTime }, | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMin.FullFrameTime }, | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMax.FullFrameTime }, | ||
} | ||
}, | ||
new DebugUI.ValueTuple | ||
{ | ||
displayName = "CPU Main Thread Frame", | ||
values = new[] | ||
{ | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleAverage.MainThreadCPUFrameTime }, | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMin.MainThreadCPUFrameTime }, | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMax.MainThreadCPUFrameTime }, | ||
} | ||
}, | ||
new DebugUI.ValueTuple | ||
{ | ||
displayName = "CPU Render Thread Frame", | ||
values = new[] | ||
{ | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleAverage.RenderThreadCPUFrameTime }, | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMin.RenderThreadCPUFrameTime }, | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMax.RenderThreadCPUFrameTime }, | ||
} | ||
}, | ||
new DebugUI.ValueTuple | ||
{ | ||
displayName = "CPU Present Wait", | ||
values = new[] | ||
{ | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleAverage.MainThreadCPUPresentWaitTime }, | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMin.MainThreadCPUPresentWaitTime }, | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMax.MainThreadCPUPresentWaitTime }, | ||
} | ||
}, | ||
new DebugUI.ValueTuple | ||
{ | ||
displayName = "GPU Frame", | ||
values = new[] | ||
{ | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleAverage.GPUFrameTime }, | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMin.GPUFrameTime }, | ||
new DebugUI.Value { refreshRate = k_RefreshRate, formatString = k_MsFormatString, getter = () => m_FrameHistory.SampleMax.GPUFrameTime }, | ||
} | ||
} | ||
} | ||
}); | ||
|
||
list.Add(new DebugUI.Foldout | ||
{ | ||
displayName = "Bottlenecks", | ||
children = | ||
{ | ||
#if UNITY_EDITOR | ||
new DebugUI.Container { displayName = "Not supported in Editor" } | ||
#else | ||
new DebugUI.ProgressBarValue { displayName = "CPU", getter = () => m_BottleneckHistory.Histogram.CPU }, | ||
new DebugUI.ProgressBarValue { displayName = "GPU", getter = () => m_BottleneckHistory.Histogram.GPU }, | ||
new DebugUI.ProgressBarValue { displayName = "Present limited", getter = () => m_BottleneckHistory.Histogram.PresentLimited }, | ||
new DebugUI.ProgressBarValue { displayName = "Balanced", getter = () => m_BottleneckHistory.Histogram.Balanced }, | ||
#endif | ||
} | ||
}); | ||
#if RTPROFILER_DEBUG | ||
list.Add(new DebugUI.Foldout | ||
{ | ||
displayName = "Realtime Profiler Debug", | ||
children = | ||
{ | ||
new DebugUI.IntField | ||
{ | ||
displayName = "Frame Time Sample History Size", | ||
getter = () => SampleHistorySize, | ||
setter = (value) => { SampleHistorySize = value; }, | ||
min = () => 1, | ||
max = () => 100 | ||
}, | ||
new DebugUI.IntField | ||
{ | ||
displayName = "Bottleneck History Size", | ||
getter = () => BottleneckHistorySize, | ||
setter = (value) => { BottleneckHistorySize = value; }, | ||
min = () => 1, | ||
max = () => 100 | ||
}, | ||
new DebugUI.IntField | ||
{ | ||
displayName = "Force VSyncCount", | ||
min = () => - 1, | ||
max = () => 4, | ||
getter = () => QualitySettings.vSyncCount, | ||
setter = (value) => { QualitySettings.vSyncCount = value; } | ||
}, | ||
new DebugUI.IntField | ||
{ | ||
displayName = "Force TargetFrameRate", | ||
min = () => - 1, | ||
max = () => 1000, | ||
getter = () => Application.targetFrameRate, | ||
setter = (value) => { Application.targetFrameRate = value; } | ||
}, | ||
} | ||
}); | ||
#endif | ||
} | ||
|
||
internal void Reset() | ||
{ | ||
m_BottleneckHistory.Clear(); | ||
m_FrameHistory.Clear(); | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.