102 lines
5.2 KiB
C#
102 lines
5.2 KiB
C#
|
|
using System.Collections;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.IO;
|
||
|
|
using System.Text;
|
||
|
|
using Unity.Profiling;
|
||
|
|
using UnityEngine;
|
||
|
|
using UnityEngine.UI;
|
||
|
|
|
||
|
|
namespace TKS
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// UI 층 구조 실측(PD 2026-11-10 캔버스 분할 검증) — 지금 화면의 렌더 통계(배치 · 드로우콜 · SetPass)와
|
||
|
|
/// 켜진 캔버스마다 그래픽 수 · 등급 · 레이캐스터 · 매 프레임 움직이는 요소(UiPulse · UiPop · 스크롤 내용 · 미니맵 · 커서)를 기록한다.
|
||
|
|
/// 「매 프레임 재구성 그래픽」 = 움직이는 요소가 든 캔버스들의 그래픽 수 합(캔버스는 자식 하나만 바뀌어도 전체를 다시 묶음).
|
||
|
|
/// </summary>
|
||
|
|
public static class UiLayerProbe
|
||
|
|
{
|
||
|
|
static ProfilerRecorder batches;
|
||
|
|
static ProfilerRecorder draws;
|
||
|
|
static ProfilerRecorder setPass;
|
||
|
|
|
||
|
|
static void Begin()
|
||
|
|
{
|
||
|
|
if (!batches.Valid) batches = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Batches Count");
|
||
|
|
if (!draws.Valid) draws = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Draw Calls Count");
|
||
|
|
if (!setPass.Valid) setPass = ProfilerRecorder.StartNew(ProfilerCategory.Render, "SetPass Calls Count");
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>몇 프레임 렌더 뒤 측정 → 로그 한 줄 + `ui_layers.csv`(캔버스별 행) 추가.</summary>
|
||
|
|
public static IEnumerator Measure(string shot, System.Action<string> log, string dir)
|
||
|
|
{
|
||
|
|
Begin();
|
||
|
|
for (int i = 0; i < 4; i++) yield return null;
|
||
|
|
long b = batches.Valid ? batches.LastValue : -1;
|
||
|
|
long d = draws.Valid ? draws.LastValue : -1;
|
||
|
|
long sp = setPass.Valid ? setPass.LastValue : -1;
|
||
|
|
#if UNITY_EDITOR
|
||
|
|
if (b <= 0) b = UnityEditor.UnityStats.batches;
|
||
|
|
if (d <= 0) d = UnityEditor.UnityStats.drawCalls;
|
||
|
|
if (sp <= 0) sp = UnityEditor.UnityStats.setPassCalls;
|
||
|
|
#endif
|
||
|
|
var movers = Movers();
|
||
|
|
var frameCanvases = new HashSet<Canvas>();
|
||
|
|
foreach (var m in movers)
|
||
|
|
{
|
||
|
|
var c = m.GetComponentInParent<Canvas>();
|
||
|
|
if (c != null) frameCanvases.Add(c);
|
||
|
|
}
|
||
|
|
var rows = new StringBuilder();
|
||
|
|
int roots = 0, nested = 0, graphics = 0, frameGraphics = 0;
|
||
|
|
foreach (var c in Object.FindObjectsByType<Canvas>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
|
||
|
|
{
|
||
|
|
if (!c.isActiveAndEnabled) continue;
|
||
|
|
int n = GraphicRegistry.GetGraphicsForCanvas(c).Count;
|
||
|
|
if (c.isRootCanvas) roots++;
|
||
|
|
else nested++;
|
||
|
|
graphics += n;
|
||
|
|
bool frame = frameCanvases.Contains(c);
|
||
|
|
if (frame) frameGraphics += n;
|
||
|
|
var tag = c.GetComponent<UiLayerInfo>();
|
||
|
|
rows.Append(shot).Append(',').Append(Path(c.transform)).Append(',').Append(c.isRootCanvas ? "root" : "nested").Append(',')
|
||
|
|
.Append(tag != null ? tag.rate.ToString() : "-").Append(',').Append(n).Append(',')
|
||
|
|
.Append(c.GetComponent<GraphicRaycaster>() != null ? "ray" : "-").Append(',').Append(frame ? "frame" : "-").Append('\n');
|
||
|
|
}
|
||
|
|
log("layers " + shot + " batches=" + b + " drawcalls=" + d + " setpass=" + sp + " canvases=" + roots + "+" + nested + " graphics=" + graphics + " frameRebuildGraphics=" + frameGraphics);
|
||
|
|
try
|
||
|
|
{
|
||
|
|
string csv = System.IO.Path.Combine(dir, "ui_layers.csv");
|
||
|
|
if (!File.Exists(csv)) File.WriteAllText(csv, "shot,canvas,kind,rate,graphics,raycaster,frame_mover\n", new UTF8Encoding(true));
|
||
|
|
File.AppendAllText(csv, rows.ToString(), new UTF8Encoding(false));
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>매 프레임 바뀌는 요소(켜진 것만).</summary>
|
||
|
|
static List<Transform> Movers()
|
||
|
|
{
|
||
|
|
var list = new List<Transform>();
|
||
|
|
foreach (var p in Object.FindObjectsByType<OutGame.UiPulse>(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) list.Add(p.transform);
|
||
|
|
foreach (var p in Object.FindObjectsByType<OutGame.UiPop>(FindObjectsInactive.Exclude, FindObjectsSortMode.None)) list.Add(p.transform);
|
||
|
|
foreach (var s in Object.FindObjectsByType<ScrollRect>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
|
||
|
|
if (s.content != null) list.Add(s.content);
|
||
|
|
foreach (var t in Object.FindObjectsByType<RectTransform>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
|
||
|
|
{
|
||
|
|
// 월드맵 커서(위아래 흔들림) · 전투 미니맵 시야 사각형(카메라 이동) · 유닛 점(이동)
|
||
|
|
if (t.name == "cursor") list.Add(t);
|
||
|
|
else if (t.name == "View" && t.parent != null && (t.parent.name == "Minimap" || t.parent.name == "MinimapLive")) list.Add(t);
|
||
|
|
}
|
||
|
|
return list;
|
||
|
|
}
|
||
|
|
|
||
|
|
static string Path(Transform t)
|
||
|
|
{
|
||
|
|
var s = t.name;
|
||
|
|
for (var p = t.parent; p != null; p = p.parent) s = p.name + "/" + s;
|
||
|
|
return s.Replace(',', ' ');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|