A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3
4namespace UnityEngine.Rendering
5{
6 /// <summary>
7 /// Represents timing data captured from a single frame.
8 /// </summary>
9 internal struct FrameTimeSample
10 {
11 internal float FramesPerSecond;
12 internal float FullFrameTime;
13 internal float MainThreadCPUFrameTime;
14 internal float MainThreadCPUPresentWaitTime;
15 internal float RenderThreadCPUFrameTime;
16 internal float GPUFrameTime;
17
18 internal FrameTimeSample(float initValue)
19 {
20 FramesPerSecond = initValue;
21 FullFrameTime = initValue;
22 MainThreadCPUFrameTime = initValue;
23 MainThreadCPUPresentWaitTime = initValue;
24 RenderThreadCPUFrameTime = initValue;
25 GPUFrameTime = initValue;
26 }
27 };
28
29 /// <summary>
30 /// Container class for sample history with helpers to calculate min, max and average in one pass.
31 /// </summary>
32 class FrameTimeSampleHistory
33 {
34 public FrameTimeSampleHistory(int initialCapacity)
35 {
36 m_Samples.Capacity = initialCapacity;
37 }
38
39 List<FrameTimeSample> m_Samples = new();
40
41 internal FrameTimeSample SampleAverage;
42 internal FrameTimeSample SampleMin;
43 internal FrameTimeSample SampleMax;
44
45 internal void Add(FrameTimeSample sample)
46 {
47 m_Samples.Add(sample);
48 }
49
50 // Helper functions
51
52 static Func<float, float, float> s_SampleValueAdd = (float value, float other) =>
53 {
54 return value + other;
55 };
56
57 static Func<float, float, float> s_SampleValueMin = (float value, float other) =>
58 {
59 return other > 0 ? Mathf.Min(value, other) : value;
60 };
61
62 static Func<float, float, float> s_SampleValueMax = (float value, float other) =>
63 {
64 return Mathf.Max(value, other);
65 };
66
67 static Func<float, float, float> s_SampleValueCountValid = (float value, float other) =>
68 {
69 return other > 0 ? value + 1 : value;
70 };
71
72 static Func<float, float, float> s_SampleValueEnsureValid = (float value, float other) =>
73 {
74 return other > 0 ? value : 0;
75 };
76
77 static Func<float, float, float> s_SampleValueDivide = (float value, float other) =>
78 {
79 return other > 0 ? value / other : 0;
80 };
81
82 internal void ComputeAggregateValues()
83 {
84 void ForEachSampleMember(ref FrameTimeSample aggregate, FrameTimeSample sample, Func<float, float, float> func)
85 {
86 aggregate.FramesPerSecond = func(aggregate.FramesPerSecond, sample.FramesPerSecond);
87 aggregate.FullFrameTime = func(aggregate.FullFrameTime, sample.FullFrameTime);
88 aggregate.MainThreadCPUFrameTime = func(aggregate.MainThreadCPUFrameTime, sample.MainThreadCPUFrameTime);
89 aggregate.MainThreadCPUPresentWaitTime = func(aggregate.MainThreadCPUPresentWaitTime, sample.MainThreadCPUPresentWaitTime);
90 aggregate.RenderThreadCPUFrameTime = func(aggregate.RenderThreadCPUFrameTime, sample.RenderThreadCPUFrameTime);
91 aggregate.GPUFrameTime = func(aggregate.GPUFrameTime, sample.GPUFrameTime);
92 };
93
94 FrameTimeSample average = new();
95 FrameTimeSample min = new(float.MaxValue);
96 FrameTimeSample max = new(float.MinValue);
97 FrameTimeSample numValidSamples = new(); // Using the struct to record how many valid samples each field has
98
99 for (int i = 0; i < m_Samples.Count; i++)
100 {
101 var s = m_Samples[i];
102
103 ForEachSampleMember(ref min, s, s_SampleValueMin);
104 ForEachSampleMember(ref max, s, s_SampleValueMax);
105 ForEachSampleMember(ref average, s, s_SampleValueAdd);
106 ForEachSampleMember(ref numValidSamples, s, s_SampleValueCountValid);
107 }
108
109 ForEachSampleMember(ref min, numValidSamples, s_SampleValueEnsureValid);
110 ForEachSampleMember(ref max, numValidSamples, s_SampleValueEnsureValid);
111 ForEachSampleMember(ref average, numValidSamples, s_SampleValueDivide);
112
113 SampleAverage = average;
114 SampleMin = min;
115 SampleMax = max;
116 }
117
118 internal void DiscardOldSamples(int sampleHistorySize)
119 {
120 Debug.Assert(sampleHistorySize > 0, "Invalid sampleHistorySize");
121
122 while (m_Samples.Count >= sampleHistorySize)
123 m_Samples.RemoveAt(0);
124
125 m_Samples.Capacity = sampleHistorySize;
126 }
127
128 internal void Clear()
129 {
130 m_Samples.Clear();
131 }
132 }
133}