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<FindClassDelegate>();
+            var newGlobalRef = newGlobalRefPtr.GetUnsafeDelegate<NewGlobalRefDelegate>();
+            var getFieldId = getFieldIdPtr.GetUnsafeDelegate<GetFieldIdDelegate>();
+            var getMethod = getMethodPtr.GetUnsafeDelegate<GetMethodIdDelegate>();
+            var newObject = newObjectPtr.GetUnsafeDelegate<NewObjectDelegate>();
+            var setDoubleField = setDoubleFieldPtr.GetUnsafeDelegate<SetDoubleFieldDelegate>();
+
+            var javaClass = findClass(jEnv, javaClassName);
+            var newGlobal = newGlobalRef(jEnv, javaClass._value);
+            var constructor = getMethod(jEnv, javaClass, GetCCharSequence("<init>"), 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