Files
HauntedBloodlines/Assets/Obi/Scripts/Common/Utils/ObiProfiler.cs
2025-05-29 22:31:40 +03:00

216 lines
5.8 KiB
C#

using System;
using UnityEngine;
namespace Obi
{
[DisallowMultipleComponent]
public class ObiProfiler : MonoBehaviour
{
[Header("Appearance")]
public GUISkin skin;
public Color threadColor = Color.white;
public Color taskColor = new Color(0.1f, 1, 0.2f);
public Color parallelTaskColor = new Color(1,0.8f,0.2f);
//public Color idleColor = new Color(0.7f,0.7f,0.7f);
public Color renderTaskColor = new Color(0.2f, 0.7f, 1.0f);
public Color defaultTaskColor = new Color(1, 0.5f, 0.2f);
[Header("Visualization")]
public bool showPercentages = false;
public int profileThrottle = 30;
private Oni.ProfileInfo[] info;
private double frameStart;
private double frameEnd;
private int frameCounter = 0;
private int yPos = 25;
private bool profiling = false;
private float zoom = 1;
private Vector2 scrollPosition = Vector2.zero;
private static ObiProfiler _instance;
private void Awake()
{
if (_instance != null && _instance != this)
DestroyImmediate(this);
else{
_instance = this;
}
}
public void OnDestroy(){
#if (OBI_ONI_SUPPORTED)
_instance = null;
Oni.EnableProfiler(false);
#endif
}
private void OnEnable()
{
#if (OBI_ONI_SUPPORTED)
if (_instance != null && _instance.profiling)
Oni.EnableProfiler(true);
#endif
}
private void OnDisable()
{
#if (OBI_ONI_SUPPORTED)
if (_instance != null)
Oni.EnableProfiler(false);
#endif
}
public static void EnableProfiler()
{
#if (OBI_ONI_SUPPORTED)
if (_instance != null)
{
_instance.profiling = true;
if (_instance.isActiveAndEnabled)
Oni.EnableProfiler(true);
}
#endif
}
public static void DisableProfiler()
{
#if (OBI_ONI_SUPPORTED)
if (_instance != null)
{
_instance.profiling = false;
Oni.EnableProfiler(false);
}
#endif
}
public static void BeginSample(string name, byte type)
{
#if (OBI_ONI_SUPPORTED)
if (_instance != null)
Oni.BeginSample(name, type);
#endif
}
public static void EndSample()
{
#if (OBI_ONI_SUPPORTED)
if (_instance != null)
Oni.EndSample();
#endif
}
private void UpdateProfilerInfo(){
#if (OBI_ONI_SUPPORTED)
frameCounter--;
if (frameCounter <= 0)
{
int count = Oni.GetProfilingInfoCount();
info = new Oni.ProfileInfo[count];
Oni.GetProfilingInfo(info,count);
frameCounter = profileThrottle;
// Calculate frame duration:
frameStart = double.MaxValue;
frameEnd = double.MinValue;
foreach (Oni.ProfileInfo i in info){
frameStart = Math.Min(frameStart,i.start);
frameEnd = Math.Max(frameEnd,i.end);
}
}
Oni.ClearProfiler();
#endif
}
public void OnGUI()
{
#if (OBI_ONI_SUPPORTED)
if (Event.current.type == EventType.Layout)
UpdateProfilerInfo();
if (info == null)
return;
GUI.skin = skin;
int toolbarHeight = 20;
int threadHeight = 20;
int scrollViewWidth = (int)(Screen.width / zoom);
double frameDuration = frameEnd - frameStart;
// Toolbar:
GUI.BeginGroup(new Rect(0,0,Screen.width,toolbarHeight),"","Box");
GUI.Label(new Rect(5,0,50,toolbarHeight),"Zoom:");
zoom = GUI.HorizontalSlider(new Rect(50,5,100,toolbarHeight),zoom,0.005f,1);
GUI.Label(new Rect(Screen.width - 100,0,100,toolbarHeight),(frameDuration/1000.0f).ToString("0.###") + " ms/frame");
GUI.EndGroup();
// Timeline view:
scrollPosition = GUI.BeginScrollView(new Rect(0, toolbarHeight, Screen.width, Screen.height-20), scrollPosition,
new Rect(0, 0, scrollViewWidth, yPos+30)); // height depends on amount of threads.
GUI.color = threadColor;
GUI.Label(new Rect(5,0,200,20),"Thread 1");
GUI.Box(new Rect(0, 0, scrollViewWidth, 40),"","Thread");
yPos = 25;
uint currentThreadId = 0;
uint currentLevel = 0;
foreach (Oni.ProfileInfo i in info)
{
uint threadId = (i.info & (uint)Oni.ProfileMask.ThreadIdMask) >> 16;
uint level = (i.info & (uint)Oni.ProfileMask.StackLevelMask) >> 8;
uint type = i.info & (uint)Oni.ProfileMask.TypeMask;
if (currentThreadId != threadId){
yPos += threadHeight+1;
GUI.color = threadColor;
GUI.Label(new Rect(5,yPos+5,200,20),"Thread "+(threadId+1));
GUI.Box(new Rect(0, yPos+5, scrollViewWidth, 40),"","Thread");
yPos += 30;
}else if (currentLevel != level){
yPos += threadHeight+1;
}
currentLevel = level;
currentThreadId = threadId;
switch(type){
case 0: GUI.color = taskColor; break;
//case 1: GUI.color = idleColor; break;
case 2: GUI.color = parallelTaskColor; break;
case 3: GUI.color = renderTaskColor; break;
default: GUI.color = defaultTaskColor; break;
}
// task duration:
int taskStart = (int) ((i.start - frameStart) / frameDuration * (Screen.width-10) / zoom);
int taskEnd = (int) ((i.end - frameStart) / frameDuration * (Screen.width-10) / zoom);
int taskDuration = taskEnd-taskStart;
string name;
if (showPercentages)
{
double pctg = (i.end-i.start)/frameDuration*100;
name = i.name + " ("+pctg.ToString("0.#")+"%)";
}
else{
double ms = (i.end-i.start)/1000.0f;
name = i.name + " ("+ms.ToString("0.###")+"ms)";
}
GUI.Box(new Rect(taskStart, yPos, taskDuration-1, threadHeight),name,"Task");
}
GUI.EndScrollView();
#endif
}
}
}