add performance hints

This commit is contained in:
Emmanuel Hansen 2023-07-20 13:35:07 +00:00
parent 61ba5e7bff
commit ff3099e4a1
10 changed files with 189 additions and 7 deletions

View File

@ -36,6 +36,12 @@ namespace LibRyujinx
[DllImport("libryujinxjni")]
private extern static JStringLocalRef createString(JEnvRef jEnv, IntPtr ch);
[DllImport("libryujinxjni")]
internal extern static void setRenderingThread();
[DllImport("libryujinxjni")]
internal extern static void onFrameEnd(double time);
public delegate IntPtr JniCreateSurface(IntPtr native_surface, IntPtr instance);
[UnmanagedCallersOnly(EntryPoint = "JNI_OnLoad")]
@ -279,6 +285,11 @@ namespace LibRyujinx
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsRendererRunLoop")]
public static void JniRunLoopNative(JEnvRef jEnv, JObjectLocalRef jObj)
{
SetSwapBuffersCallback(() =>
{
var time = SwitchDevice.EmulationContext.Statistics.GetGameFrameTime();
onFrameEnd(time);
});
RunLoop();
}

View File

@ -165,6 +165,11 @@ namespace LibRyujinx
return;
}
if (Ryujinx.Common.SystemInfo.SystemInfo.IsBionic)
{
setRenderingThread();
}
if (device.WaitFifo())
{
device.Statistics.RecordFifoStart();

View File

@ -477,6 +477,9 @@ namespace Ryujinx.Graphics.Vulkan
{
_gd.SwapchainApi.QueuePresent(_gd.Queue, presentInfo);
}
//While this does nothing in most cases, it's useful to notify the end of the frame.
swapBuffersCallback?.Invoke();
}
public override void SetAntiAliasing(AntiAliasing effect)

View File

@ -20,6 +20,7 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:largeHeap="true"
android:appCategory="game"
android:theme="@style/Theme.RyujinxAndroid"
tools:targetApi="31">
<activity

View File

@ -36,4 +36,10 @@ void* _ryujinxNative = NULL;
// Ryujinx imported functions
bool (*initialize)(char*) = NULL;
long _renderingThreadId = 0;
long _currentRenderingThreadId = 0;
JavaVM* _vm = nullptr;
jobject _mainActivity = nullptr;
jclass _mainActivityClass = nullptr;
#endif //RYUJINXNATIVE_RYUIJNX_H

View File

@ -17,6 +17,31 @@
// }
#include "ryuijnx.h"
#include "pthread.h"
#include <chrono>
jmethodID _updateFrameTime;
JNIEnv* _rendererEnv = nullptr;
std::chrono::time_point<std::chrono::steady_clock, std::chrono::nanoseconds> _currentTimePoint;
JNIEnv* getEnv(bool isRenderer){
JNIEnv* env;
if(isRenderer){
env = _rendererEnv;
}
if(env != nullptr)
return env;
auto result = _vm->AttachCurrentThread(&env, NULL);
return env;
}
void detachEnv(){
auto result = _vm->DetachCurrentThread();
}
extern "C"
{
@ -129,3 +154,38 @@ jstring createString(
}
extern "C"
JNIEXPORT jlong JNICALL
Java_org_ryujinx_android_MainActivity_getRenderingThreadId(JNIEnv *env, jobject thiz) {
return _currentRenderingThreadId;
}
extern "C"
void setRenderingThread(){
auto currentId = pthread_self();
_currentRenderingThreadId = currentId;
_renderingThreadId = currentId;
_currentTimePoint = std::chrono::high_resolution_clock::now();
}
extern "C"
JNIEXPORT void JNICALL
Java_org_ryujinx_android_MainActivity_initVm(JNIEnv *env, jobject thiz) {
JavaVM* vm = nullptr;
auto success = env->GetJavaVM(&vm);
_vm = vm;
_mainActivity = thiz;
_mainActivityClass = env->GetObjectClass(thiz);
}
extern "C"
void onFrameEnd(double time){
auto env = getEnv(true);
auto cl = env->FindClass("org/ryujinx/android/MainActivity");
_updateFrameTime = env->GetStaticMethodID( cl , "updateRenderSessionPerformance", "(J)V");
auto now = std::chrono::high_resolution_clock::now();
auto nano = std::chrono::duration_cast<std::chrono::nanoseconds>(now-_currentTimePoint).count();
env->CallStaticVoidMethod(cl, _updateFrameTime,
nano);
}

View File

@ -1,13 +1,10 @@
package org.ryujinx.android
import android.content.Context
import android.os.ParcelFileDescriptor
import android.os.Build
import android.view.MotionEvent
import android.view.SurfaceHolder
import android.view.SurfaceView
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.ryujinx.android.viewmodels.GameModel
import org.ryujinx.android.viewmodels.MainViewModel
import org.ryujinx.android.viewmodels.QuickSettings
@ -15,6 +12,7 @@ import kotlin.concurrent.thread
import kotlin.math.roundToInt
class GameHost(context: Context?, val controller: GameController, val mainViewModel: MainViewModel) : SurfaceView(context), SurfaceHolder.Callback {
private var _renderingThreadWatcher: Thread? = null
private var _height: Int = 0
private var _width: Int = 0
private var _updateThread: Thread? = null
@ -168,7 +166,25 @@ class GameHost(context: Context?, val controller: GameController, val mainViewMo
}
private fun runGame() : Unit{
// RenderingThreadWatcher
_renderingThreadWatcher = thread(start = true) {
var threadId = 0L;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
mainViewModel.performanceManager?.enable()
while (_isStarted) {
Thread.sleep(1000)
var newthreadId = mainViewModel.activity.getRenderingThreadId()
if (threadId != newthreadId) {
mainViewModel.performanceManager?.closeCurrentRenderingSession()
}
threadId = newthreadId;
if (threadId != 0L) {
mainViewModel.performanceManager?.initializeRenderingSession(threadId)
}
}
}
}
_nativeRyujinx.graphicsRendererRunLoop()
}
}

View File

@ -33,23 +33,39 @@ import org.ryujinx.android.views.MainView
class MainActivity : ComponentActivity() {
var physicalControllerManager: PhysicalControllerManager
private var mainViewModel: MainViewModel? = null
private var _isInit: Boolean = false
var storageHelper: SimpleStorageHelper? = null
companion object {
var mainViewModel: MainViewModel? = null
var AppPath : String?
var StorageHelper: SimpleStorageHelper? = null
init {
AppPath = ""
}
@JvmStatic
fun updateRenderSessionPerformance(gameTime : Long)
{
if(gameTime <= 0)
return
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
mainViewModel?.performanceManager?.updateRenderingSessionTime(gameTime)
}
}
}
init {
physicalControllerManager = PhysicalControllerManager(this)
storageHelper = SimpleStorageHelper(this)
StorageHelper = storageHelper
System.loadLibrary("ryujinxjni")
initVm()
}
external fun getRenderingThreadId() : Long
external fun initVm()
fun setFullScreen() :Unit {
requestedOrientation =
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;

View File

@ -0,0 +1,49 @@
package org.ryujinx.android
import android.os.Build
import android.os.PerformanceHintManager
import androidx.annotation.RequiresApi
class PerformanceManager(val performanceHintManager: PerformanceHintManager) {
private var _isEnabled: Boolean = false
private var renderingSession: PerformanceHintManager.Session? = null
val DEFAULT_TARGET_NS = 16666666L
@RequiresApi(Build.VERSION_CODES.S)
fun initializeRenderingSession(threadId : Long){
if(!_isEnabled || renderingSession != null)
return
var threads = IntArray(1)
threads[0] = threadId.toInt()
renderingSession = performanceHintManager.createHintSession(threads, DEFAULT_TARGET_NS)
}
@RequiresApi(Build.VERSION_CODES.S)
fun closeCurrentRenderingSession() {
if (_isEnabled)
renderingSession?.apply {
renderingSession = null
this.close()
}
}
fun enable(){
_isEnabled = true
}
@RequiresApi(Build.VERSION_CODES.S)
fun updateRenderingSessionTime(newTime : Long){
if(!_isEnabled)
return
var effectiveTime = newTime
if(newTime < DEFAULT_TARGET_NS)
effectiveTime = DEFAULT_TARGET_NS
renderingSession?.apply {
this.reportActualWorkDuration(effectiveTime)
}
}
}

View File

@ -1,18 +1,33 @@
package org.ryujinx.android.viewmodels
import android.annotation.SuppressLint
import android.content.Context
import android.os.Build
import android.os.PerformanceHintManager
import androidx.compose.runtime.MutableState
import androidx.navigation.NavHostController
import org.ryujinx.android.GameHost
import org.ryujinx.android.MainActivity
import org.ryujinx.android.PerformanceManager
@SuppressLint("WrongConstant")
class MainViewModel(val activity: MainActivity) {
var performanceManager: PerformanceManager? = null
var selected: GameModel? = null
private var gameTimeState: MutableState<Double>? = null
private var gameFpsState: MutableState<Double>? = null
private var fifoState: MutableState<Double>? = null
private var navController : NavHostController? = null
var homeViewModel: HomeViewModel = HomeViewModel(activity, this,)
var homeViewModel: HomeViewModel = HomeViewModel(activity, this)
init {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
var hintService =
activity.getSystemService(Context.PERFORMANCE_HINT_SERVICE) as PerformanceHintManager
performanceManager = PerformanceManager(hintService)
}
}
fun loadGame(game:GameModel) {
var controller = navController?: return;