diff --git a/src/LibRyujinx/JniExportedMethods.cs b/src/LibRyujinx/JniExportedMethods.cs index d64760fed..62874e145 100644 --- a/src/LibRyujinx/JniExportedMethods.cs +++ b/src/LibRyujinx/JniExportedMethods.cs @@ -94,6 +94,43 @@ namespace LibRyujinx return InitializeDevice(isHostMapped); } + [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetGameStats")] + public static JObjectLocalRef JniGetGameStats(JEnvRef jEnv, JObjectLocalRef jObj) + { + var stats = GetGameStats(); + + var javaClassName = GetCCharSequence("org/ryujinx/android/viewmodels/GameStats"); + + JEnvValue value = jEnv.Environment; + ref JNativeInterface jInterface = ref value.Functions; + IntPtr findClassPtr = jInterface.FindClassPointer; + IntPtr newGlobalRefPtr = jInterface.NewGlobalRefPointer; + IntPtr getFieldIdPtr = jInterface.GetFieldIdPointer; + IntPtr getMethodPtr = jInterface.GetMethodIdPointer; + IntPtr newObjectPtr = jInterface.NewObjectPointer; + IntPtr setDoubleFieldPtr = jInterface.SetDoubleFieldPointer; + + + var findClass = findClassPtr.GetUnsafeDelegate(); + var newGlobalRef = newGlobalRefPtr.GetUnsafeDelegate(); + var getFieldId = getFieldIdPtr.GetUnsafeDelegate(); + var getMethod = getMethodPtr.GetUnsafeDelegate(); + var newObject = newObjectPtr.GetUnsafeDelegate(); + var setDoubleField = setDoubleFieldPtr.GetUnsafeDelegate(); + + var javaClass = findClass(jEnv, javaClassName); + var newGlobal = newGlobalRef(jEnv, javaClass._value); + var constructor = getMethod(jEnv, javaClass, GetCCharSequence(""), GetCCharSequence("()V")); + var newObj = newObject(jEnv, javaClass, constructor, 0); + + + setDoubleField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("Fifo"), GetCCharSequence("D")), stats.Fifo); + setDoubleField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("GameFps"), GetCCharSequence("D")), stats.GameFps); + setDoubleField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("GameTime"), GetCCharSequence("D")), stats.GameTime); + + return newObj; + } + [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceLoad")] public static JBoolean JniLoadApplicationNative(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef pathPtr) { diff --git a/src/LibRyujinx/LibRyujinx.cs b/src/LibRyujinx/LibRyujinx.cs index 4f0a049f7..f2bf5da13 100644 --- a/src/LibRyujinx/LibRyujinx.cs +++ b/src/LibRyujinx/LibRyujinx.cs @@ -100,6 +100,21 @@ namespace LibRyujinx AudioDriver = new SDL2HardwareDeviceDriver(); } + public static GameStats GetGameStats() + { + if (SwitchDevice?.EmulationContext == null) + return new GameStats(); + + var context = SwitchDevice.EmulationContext; + + return new GameStats() + { + Fifo = context.Statistics.GetFifoPercent(), + GameFps = context.Statistics.GetGameFrameRate(), + GameTime = context.Statistics.GetGameFrameTime() + }; + } + public static GameInfo GetGameInfo(Stream gameStream, bool isXci) { var gameInfo = new GameInfo(); @@ -579,4 +594,11 @@ namespace LibRyujinx public string Version; public byte[] Icon; } + + public class GameStats + { + public double Fifo; + public double GameFps; + public double GameTime; + } } \ No newline at end of file