XR SDK Stats 接口用于注册和管理统计数据。
使用 XR Stats 接口记录各个子系统之间的统计数据。浮点数是唯一支持的统计数据原始类型。
使用 UnityPluginLoad
入口点方法获取指向 XRStats 接口的指针:
IUnityXRStats* sXRStats = nullptr;
extern "C" void UNITY_INTERFACE_EXPORT UnityPluginLoad(IUnityInterfaces* unityInterfaces)
{
sXRStats = (IUnityXRStats*)unityInterfaces->GetInterface(UNITY_GET_INTERFACE_GUID(IUnityXRStats));
//...
}
使用 stats 接口注册您的子系统和各个 stat 定义:
static UnityXRStatId m_GPUFrameTimeID;
static UnityXRStatId m_DroppedFrameCountID;
static UnityXRStatId m_WorkThreadStat;
static UnitySubsystemErrorCode ExampleDisplayProvider_Start(UnitySubsystemHandle handle)
{
if (sXRStats)
{
sXRStats->RegisterStatSource(handle);
m_GPUFrameTimeID = sXRStats->RegisterStatDefinition(handle, "Example.GPUTime", kUnityXRStatOptionNone);
m_DroppedFrameCountID = sXRStats->RegisterStatDefinition(handle, "Example.DroppedFrame", kUnityXRStatOptionNone);
m_WorkThreadStat = sXRStats->RegisterStatDefinition(handle, "Example.WorkerThreadStat", kUnityXRStatOptionNone);
}
return kUnitySubsystemErrorCodeSuccess;
}
更新 Gfx 线程上的统计数据:
extern float GetLastGPUTime(); //由您的运行时提供
static void ExampleDisplayProvider_GfxThreadCall(UnitySubsystemHandle handle)
{
sXRStats->SetStatFloat(m_GPUFrameTimeID, GetLastGPUTime());
// 执行 gfx 线程的操作
}
更新主线程上的统计数据:
extern float GetDroppedFrameCount(); //由您的运行时提供
static void ExampleDisplayProvider_MainThreadCall(UnitySubsystemHandle handle)
{
sXRStats->SetStatFloat(m_DroppedFrameCountID, GetDroppedFrameCount());
// 执行主线程的操作
}
更新您自己的线程上统计数据,但务必调用 IncrementStatFrame
以保持该线程的当前帧与其他线程同步(内部对主线程和图形线程进行管理):
extern float GetWorkerThreadStat(); //由您的运行时提供
static void ExampleDisplayProvider_MyWorkerThread(UnitySubsystemHandle handle)
{
sXRStats->IncrementStatFrame();
sXRStats->SetStatFloat(m_WorkThreadStat, GetWorkerThreadStat());
// 执行工作线程的操作
}
当子系统停止时取消注册统计源:
static void ExampleDisplayProvider_Stop(UnitySubsystemHandle handle)
{
sXRStats->UnregisterStatSource(handle);
}
通过 SetStatFloat
更新统计数据是线程安全的。但是,注册和取消注册统计数据源不是线程安全的,只能在统计数据源生命周期的 Start 和 Stop 函数期间在主线程上完成。
处理统计数据的队列大小为 2000。该队列在所有线程和所有子系统之间共享,并且仅在帧完成时提供服务。为此,您应该将调用 SetStatFloat
的次数保持在较低的水平,以避免填满队列。
注意:队列已满时记录的任何统计数据都将丢失。
在 UnityEngine.XR.Provider
命名空间中,使用 public static bool TryGetStat(Experimental.IntegratedSubsystem xrSubsystem, string tag, out float value)
获取向您的提供程序注册和更新的统计数据:
using UnityEngine.XR.Provider;
using System.Collections.Generic;
using UnityEngine.Experimental.XR;
using UnityEngine.Experimental;
using UnityEngine;
public static class ExampleProviderStats
{
public static float GPUFrameTime()
{
float tmp;
XRStats.TryGetStat(GetFirstDisplaySubsystem(), "Example.GPUTime", out tmp);
return tmp;
}
public static int DroppedFrameCount()
{
float tmp;
XRStats.TryGetStat(GetFirstDisplaySubsystem(), "Example.DroppedFrame", out tmp);
return (int)tmp;
}
public static float MyWorkerThreadStat()
{
float tmp;
XRStats.TryGetStat(GetFirstDisplaySubsystem(), "Example.WorkerThreadStat", out tmp);
return tmp;
}
// etc...
private static IntegratedSubsystem GetFirstDisplaySubsystem()
{
List<XRDisplaySubsystem> displays = new List<XRDisplaySubsystem>();
SubsystemManager.GetInstances(displays);
if (displays.Count == 0)
{
Debug.Log("No display subsystem found.");
return null;
}
return displays[0];
}
}
编写公共访问器方法(如上面的示例所示)可以帮助用户获取统计数据,而无需筛查提供程序文档并查找注册了统计数据的子系统。
此外,一些子系统具有预定义的统计数据标签。您的提供程序可以为预定义的统计 API 提供统计数据,Unity 可通过注册子系统特定的统计数据标签进行公开(例如:Headers/XR/UnityXRDisplayStats.h
)。