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}