using System;
using System.Collections;
using System.IO;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using Unity.EditorCoroutines.Editor;
using Unity.Collections;
using Unity.Burst;
using Unity.Jobs;
using Unity.Mathematics;
public class FrameDebugExamplle : EditorWindow
{
static Type s_frameDebugType = Type.GetType("UnityEditorInternal.FrameDebuggerUtility,UnityEditor");
static Type s_frameDebugWindowsType = Type.GetType("UnityEditor.FrameDebuggerWindow,UnityEditor");
static bool s_HasLatSample;
static NativeArray<Color> s_LastSample2DColor;
static NativeArray<Color> s_FirstSample2DColor;
static int s_FinalPixel = 0;
static int s_ProcessPixel = 0;
static int s_VertexCount = 0;
static int s_StartDC;
static int s_EndDC;
static string s_Result;
static string DirectoryPath = "Assets/采样";
static EditorWindow s_FrameDebugWindows;
[MenuItem("Example/开始")]
public static void ShowWindow()
{
OpenAndEnableFrameDebugger();
}
void OnGUI()
{
int count = (int)s_frameDebugType.GetProperty("count", BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static).GetValue(null);
if (count == 0)
{
//强制打开framedebugger窗口
OpenAndEnableFrameDebugger();
}
GUILayout.Label(string.Format($"DC区间 0 - {count}"));
s_StartDC = Mathf.Clamp(EditorGUILayout.IntField("开始", s_StartDC),0,count - 1);
s_EndDC = Mathf.Max(Mathf.Clamp(EditorGUILayout.IntField("结束", s_EndDC),0,count), s_StartDC);
if (GUILayout.Button($"开始截取: {s_StartDC}DC-{s_EndDC}DC", GUILayout.Width(200), GUILayout.Height(50)))
{
OpenAndEnableFrameDebugger();
EditorCoroutineUtility.StartCoroutineOwnerless(StartGetData());
}
GUILayout.Label(s_Result);
}
//等N帧
IEnumerator WaitFive(int count)
{
for (int i = 0; i < count; i++)
{
yield return null;
}
}
//开始获取数据
IEnumerator StartGetData()
{
s_VertexCount = 0;
s_ProcessPixel = 0;
s_FinalPixel = 0;
s_Result = string.Empty;
s_HasLatSample = false;
FileUtil.DeleteFileOrDirectory(DirectoryPath);
Directory.CreateDirectory(DirectoryPath);
for (int i = s_StartDC; i <= s_EndDC; i++)
{
s_frameDebugType.GetProperty("limit", BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static).SetValue(null, i);
yield return WaitFive(1); //等1帧
RefreshFrameDebuggerWindows();
yield return WaitFive(1); //等1帧
//截图
Texture2D textureSample = TextureSample();
Color[] colorBuffer = textureSample.GetPixels();
if (textureSample)
{
File.WriteAllBytes($"{DirectoryPath}/开始{i}.jpg", textureSample.EncodeToJPG());
if (!s_FirstSample2DColor.IsCreated)
{
s_FirstSample2DColor = new NativeArray<Color>(colorBuffer, Allocator.Persistent);
}
if (s_HasLatSample)
{
//统计差异颜色数
var Job = new JobDiff
{
result = new NativeArray<int>(1, Allocator.TempJob),
current = new NativeArray<Color>(colorBuffer, Allocator.TempJob),
last = s_LastSample2DColor,
};
Job.Schedule(s_LastSample2DColor.Length, new JobHandle()).Complete();
s_ProcessPixel += Job.result[0];
Job.current.Dispose();
Job.result.Dispose();
s_LastSample2DColor.Dispose();
//统计面数
EditorWindow windows = EditorWindow.GetWindow(s_frameDebugWindowsType);
FieldInfo info = windows.GetType().GetField("m_CurEventData", BindingFlags.Instance | BindingFlags.NonPublic);
object FrameDebuggerEventData = info.GetValue(windows);
if (FrameDebuggerEventData != null)
{
s_VertexCount += (int)FrameDebuggerEventData.GetType().GetField("vertexCount", BindingFlags.Instance | BindingFlags.Public).GetValue(FrameDebuggerEventData);
}
}
if (i != s_EndDC)
{
s_HasLatSample = true;
s_LastSample2DColor = new NativeArray<Color>(colorBuffer, Allocator.Persistent);
}
else
{
//统计最后一张与第一张之间的差异
Texture2D diff = textureSample;
var Job = new JobFinalDiff
{
result = new NativeArray<int>(1, Allocator.TempJob),
first = s_FirstSample2DColor,
end = new NativeArray<Color>(colorBuffer, Allocator.TempJob),
};
Job.Schedule(s_FirstSample2DColor.Length, new JobHandle()).Complete();
s_FinalPixel = Job.result[0];
diff.SetPixels(Job.end.ToArray());
Job.end.Dispose();
Job.result.Dispose();
s_FirstSample2DColor.Dispose();
File.WriteAllBytes($"{DirectoryPath}/变化.jpg", diff.EncodeToJPG());
}
}
}
int pixelSqrt = (int)Mathf.Sqrt((s_ProcessPixel - s_FinalPixel));
int finalPixelSqrt = (int)Mathf.Sqrt(s_FinalPixel);
s_Result = $"最终像素 {finalPixelSqrt} X {finalPixelSqrt} 重复像素 {pixelSqrt} x {pixelSqrt} 总渲染顶点数 {s_VertexCount}";
AssetDatabase.Refresh();
}
static Texture2D TextureSample()
{
try
{
Texture texture = Shader.GetGlobalTexture("_CameraColorTexture");
if (!texture)
{
texture = Shader.GetGlobalTexture("_CameraOpaqueTexture");
}
if (!texture)
{
Debug.LogError("没有截到图输出错误");
}
if (texture)
{
var width = texture.width;
var height = texture.height;
RenderTexture previous = RenderTexture.active;
RenderTexture tmp = RenderTexture.GetTemporary(width, height, 0, RenderTextureFormat.Default, RenderTextureReadWrite.sRGB);
Graphics.Blit(texture, tmp);
RenderTexture.active = tmp;
Texture2D @new = new Texture2D(width, height);
@new.ReadPixels(new Rect(0, 0, width, height), 0, 0);
@new.Apply();
RenderTexture.active = previous;
return @new;
}
}
catch (Exception e)
{
Debug.LogError("没有截到图输出错误: " + e);
}
return null;
}
static void OpenAndEnableFrameDebugger()
{
EditorWindow.GetWindow(typeof(FrameDebugExamplle), true, "标题", true);
//打开frameDebug窗口
s_FrameDebugWindows = EditorWindow.GetWindow(s_frameDebugWindowsType);
s_frameDebugWindowsType.GetMethod("EnableIfNeeded", BindingFlags.Instance | BindingFlags.Public).Invoke(s_FrameDebugWindows, null);
}
static void RefreshFrameDebuggerWindows()
{
Type windowsType = Type.GetType("UnityEditor.FrameDebuggerWindow,UnityEditor");
var windows = EditorWindow.GetWindow(windowsType);
windowsType.GetMethod("RepaintOnLimitChange", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(windows, null);
}
[BurstCompile]
struct JobDiff : IJobFor
{
[ReadOnly] public NativeArray<Color> current;
[ReadOnly] public NativeArray<Color> last;
public NativeArray<int> result;
public void Execute(int index)
{
//干掉分支预测
result[0] += math.select(0, 1, current[index] != last[index]);
}
}
[BurstCompile]
struct JobFinalDiff : IJobFor
{
[ReadOnly] public NativeArray<Color> first;
public NativeArray<Color> end;
public NativeArray<int> result;
public void Execute(int index)
{
if(end[index] != first[index])
{
end[index] = Color.red;
result[0]++;
}
}
}
}