본문 바로가기
개발/Unity

유니티 - OnGUI, ProfilerRecorder로 런타임 드로우 콜 확인하기 (How to Get Draw Call Count at Runtime)

by 피로물든딸기 2022. 12. 10.
반응형

Unity 전체 링크

 

참고 

- OnGUI로 실시간 초당 프레임 수 확인하기

- 드로우 콜 횟수 최적화하기

- ProfilerRecorder 메뉴얼 

- Rendering Profiler module 메뉴얼

 

유니티 게임 씬에서 Stats에서는 성능과 관련된 정보를 볼 수 있다.

 

유니티 에디터에서 말고 runtime에 직접 확인할 수 있도록 해보자.


- ProfilerRecorder 메뉴얼

- Rendering Profiler module 메뉴얼

 

유니티에서 제공하는 ProfilerRecorder를 이용하면 위의 통계 정보를 확인할 수 있다.

위의 링크에 제시된 코드는 다음과 같다.

    void OnEnable()
    {
        setPassCallsRecorder 
            = ProfilerRecorder.StartNew(ProfilerCategory.Render, "SetPass Calls Count");
        drawCallsRecorder 
            = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Draw Calls Count");
        verticesRecorder 
            = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Vertices Count");
    }

 

만약 Shadow casters를 보고 싶다면 아래의 코드를 추가하고 링크의 예시를 참고하여 코드를 추가하면 된다.

    ProfilerRecorder shadowCastersRecorder;
    
    void OnEnable()
    {
         shadowCastersRecorder 
            = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Shadow Casters Count");
    }

 

또한 GetRecorderFrameAverage에 unsafe라는 키워드가 에러가 발생할 수 있다.

 

해당 에러코드는 다음과 같다.

error CS0227: 
Unsafe code may only appear if compiling with /unsafe. 
Enable "Allow 'unsafe' code" in Player Settings to fix this error.


[Edit] → [Project Settings] → [Player]의 아래에 Allow 'unsafe' Code를 체크해주자.

 

전체 코드는 다음과 같고, 이 스크립트를 빈 오브젝트에 추가하자.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Profiling;
using System.Text;

public class StatisticsManager : MonoBehaviour
{
    string statsText;
    ProfilerRecorder setPassCallsRecorder;
    ProfilerRecorder drawCallsRecorder;
    ProfilerRecorder verticesRecorder;
    ProfilerRecorder shadowCastersRecorder;

    ProfilerRecorder systemMemoryRecorder;
    ProfilerRecorder gcMemoryRecorder;
    ProfilerRecorder mainThreadTimeRecorder;

    static double GetRecorderFrameAverage(ProfilerRecorder recorder)
    {
        var samplesCount = recorder.Capacity;
        if (samplesCount == 0)
            return 0;

        double r = 0;
        unsafe
        {
            var samples = stackalloc ProfilerRecorderSample[samplesCount];
            recorder.CopyTo(samples, samplesCount);
            for (var i = 0; i < samplesCount; ++i)
                r += samples[i].Value;
            r /= samplesCount;
        }

        return r;
    }

    void OnEnable()
    {
        setPassCallsRecorder 
            = ProfilerRecorder.StartNew(ProfilerCategory.Render, "SetPass Calls Count");
        drawCallsRecorder 
            = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Draw Calls Count");
        verticesRecorder 
            = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Vertices Count");
        shadowCastersRecorder 
            = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Shadow Casters Count");

        systemMemoryRecorder 
            = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "System Used Memory");
        gcMemoryRecorder 
            = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "GC Reserved Memory");
        mainThreadTimeRecorder 
            = ProfilerRecorder.StartNew(ProfilerCategory.Internal, "Main Thread", 15);
    }

    void OnDisable()
    {
        setPassCallsRecorder.Dispose();
        drawCallsRecorder.Dispose();
        verticesRecorder.Dispose();
        shadowCastersRecorder.Dispose();
    }

    void Update()
    {
        var sb = new StringBuilder(500);
        if (setPassCallsRecorder.Valid)
            sb.AppendLine($"SetPass Calls: {setPassCallsRecorder.LastValue}");
        if (drawCallsRecorder.Valid)
            sb.AppendLine($"Draw Calls: {drawCallsRecorder.LastValue}");
        if (shadowCastersRecorder.Valid)
            sb.AppendLine($"Shadow Casters : {shadowCastersRecorder.LastValue}");
        if (verticesRecorder.Valid)
            sb.AppendLine($"Vertices: {verticesRecorder.LastValue}");

        sb.AppendLine($"Frame Time: {GetRecorderFrameAverage(mainThreadTimeRecorder) * (1e-6f):F1} ms");
        sb.AppendLine($"GC Memory: {gcMemoryRecorder.LastValue / (1024 * 1024)} MB");
        sb.AppendLine($"System Memory: {systemMemoryRecorder.LastValue / (1024 * 1024)} MB");

        statsText = sb.ToString();
    }

    void OnGUI()
    {
        GUI.TextArea(new Rect(10, 30, 250, 120), statsText);
    }
}

 

게임을 실행하면 OnGUI에 의해 왼쪽 위에 런타임으로 통계 정보(드로우 콜, 메모리 등)를 확인할 수 있다.

 

실제 apk로 빌드한 후 확인한 결과는 아래와 같다.

 

Unity Plus:

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

 

Unity Pro:

 

Unity Pro

The complete solutions for professionals to create and operate.

unity.com

 

Unity 프리미엄 학습:

 

Unity Learn

Advance your Unity skills with live sessions and over 750 hours of on-demand learning content designed for creators at every skill level.

unity.com

반응형

댓글