Remy
Remy

Reputation: 5173

What is the correct usage of FrameTiming and FrameTimingManager

I'm trying to log the time the GPU takes to render a frame. To do this I found that Unity implemented a struct FrameTiming, and a class named FrameTimingManager

The FrameTiming struct has a property gpuFrameTime which sounds like exactly what I need, however the value is never set, and the documentation on it doesn't provide much help either

public double gpuFrameTime;

Description
The GPU time for a given frame, in ms.

Looking further I found the FrameTimingManager class which contains a static method for GetGpuTimerFrequency(), which has the not so helpful documentation stating only:

Returns ulong GPU timer frequency for current platform.

Description
This returns the frequency of GPU timer on the current platform, used to interpret timing results. If the platform does not support returning this value it will return 0.

Calling this method in an update loop only ever yields 0 (on both Window 10 running Unity 2019.3 and Android phone running Android 10).

private void OnEnable()
{
    frameTiming = new FrameTiming();
}

private void Update()
{
    FrameTimingManager.CaptureFrameTimings();
    var result = FrameTimingManager.GetGpuTimerFrequency();
    Debug.LogFormat("result: {0}", result); //logs 0
    var gpuFrameTime = frameTiming.gpuFrameTime;
    Debug.LogFormat("gpuFrameTime: {0}", gpuFrameTime); //logs 0
}

So what's the deal here, am I using the FrameTimeManager incorrectly, or are Windows and Android not supported (Unity mentions in the docs that not all platforms are supported, but nowhere do they give a list of supported devices..)?

Upvotes: 2

Views: 3056

Answers (1)

Remy
Remy

Reputation: 5173

While grabbing documentation links for the question I stumbled across some forum posts that shed light on the issue, so leaving it here for future reference.


The FrameTimingManager is indeed not supported for Windows, and only has limited support for Android devices, more specifically only for Android Vulkan devices. As explained by jwtan_Unity on the forums here (emphasis mine):

FrameTimingManager was introduced to support Dynamic Resolution. Thus, it is only supported on platforms that support Dynamic Resolution. These platforms are currently Xbox One, PS4, Nintendo Switch, iOS, macOS and tvOS (Metal only), Android (Vulkan only), Windows Standalone and UWP (DirectX 12 only).

Now to be able to use the FrameTimingManager.GetGpuTimerFrequency() we need to do something else first. We need to take a snapshot of the current timings using FrameTimingManager.CaptureFrameTimings first (this needs to be done every frame). From the docs:

This function triggers the FrameTimingManager to capture a snapshot of FrameTiming's data, that can then be accessed by the user.
The FrameTimingManager tries to capture as many frames as the platform allows but will only capture complete timings from finished and valid frames so the number of frames it captures may vary. This will also capture platform specific extended frame timing data if the platform supports more in depth data specifically available to it.

As explained by Timothyh_Unity on the forums hereenter link description here

CaptureFrameTimings() - This should be called once per frame(presuming you want timing data that frame). Basically this function captures a user facing collection of timing data.

So the total code to get the GPU frequency (on a supported device) would be

private void Update()
{
    FrameTimingManager.CaptureFrameTimings();
    var result = FrameTimingManager.GetGpuTimerFrequency();
    Debug.LogFormat("result: {0}", result);
}

Note that all FrameTimingManager methods are static, and do not require you to instantiate a manager first

Why none of this is properly documented by Unity beats me...

Upvotes: 4

Related Questions