forked from MeloNX/MeloNX
fix audio rebase
remove redundant sdk performance session usage remove debug code and formatting
This commit is contained in:
parent
d40dc00769
commit
06a7c0217f
@ -3,7 +3,7 @@ using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE;
|
||||
using Ryujinx.HLE.HOS.Applets;
|
||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||
using Ryujinx.HLE.Ui;
|
||||
using Ryujinx.HLE.UI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -13,17 +13,17 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace LibRyujinx.Android
|
||||
{
|
||||
internal class AndroidUiHandler : IHostUiHandler, IDisposable
|
||||
internal class AndroidUIHandler : IHostUIHandler, IDisposable
|
||||
{
|
||||
public IHostUiTheme HostUiTheme => throw new NotImplementedException();
|
||||
|
||||
public ManualResetEvent _waitEvent;
|
||||
public ManualResetEvent _responseEvent;
|
||||
private bool _isDisposed;
|
||||
private bool _isOkPressed;
|
||||
private long _input;
|
||||
|
||||
public AndroidUiHandler()
|
||||
public IHostUITheme HostUITheme => throw new NotImplementedException();
|
||||
|
||||
public AndroidUIHandler()
|
||||
{
|
||||
_waitEvent = new ManualResetEvent(false);
|
||||
_responseEvent = new ManualResetEvent(false);
|
||||
@ -47,7 +47,7 @@ namespace LibRyujinx.Android
|
||||
return _isOkPressed;
|
||||
}
|
||||
|
||||
public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText)
|
||||
public bool DisplayInputDialog(SoftwareKeyboardUIArgs args, out string userText)
|
||||
{
|
||||
LibRyujinx.setUiHandlerTitle(LibRyujinx.storeString("Software Keyboard"));
|
||||
LibRyujinx.setUiHandlerMessage(LibRyujinx.storeString(args.HeaderText ?? ""));
|
||||
@ -81,7 +81,7 @@ namespace LibRyujinx.Android
|
||||
return _isOkPressed;
|
||||
}
|
||||
|
||||
public bool DisplayMessageDialog(ControllerAppletUiArgs args)
|
||||
public bool DisplayMessageDialog(ControllerAppletUIArgs args)
|
||||
{
|
||||
string playerCount = args.PlayerCountMin == args.PlayerCountMax ? $"exactly {args.PlayerCountMin}" : $"{args.PlayerCountMin}-{args.PlayerCountMax}";
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
namespace LibRyujinx.Shared.Audio.Oboe
|
||||
{
|
||||
internal class OboeAudioBuffer
|
||||
{
|
||||
public readonly ulong DriverIdentifier;
|
||||
public readonly ulong SampleCount;
|
||||
public readonly byte[] Data;
|
||||
public ulong SamplePlayed;
|
||||
|
||||
public OboeAudioBuffer(ulong driverIdentifier, byte[] data, ulong sampleCount)
|
||||
{
|
||||
DriverIdentifier = driverIdentifier;
|
||||
Data = data;
|
||||
SampleCount = sampleCount;
|
||||
SamplePlayed = 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
using Ryujinx.Audio;
|
||||
using Ryujinx.Audio.Common;
|
||||
using Ryujinx.Audio.Integration;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
|
||||
|
||||
namespace LibRyujinx.Shared.Audio.Oboe
|
||||
{
|
||||
internal class OboeHardwareDeviceDriver : IHardwareDeviceDriver
|
||||
{
|
||||
private readonly ManualResetEvent _updateRequiredEvent;
|
||||
private readonly ManualResetEvent _pauseEvent;
|
||||
private readonly ConcurrentDictionary<OboeHardwareDeviceSession, byte> _sessions;
|
||||
|
||||
public OboeHardwareDeviceDriver()
|
||||
{
|
||||
_updateRequiredEvent = new ManualResetEvent(false);
|
||||
_pauseEvent = new ManualResetEvent(true);
|
||||
_sessions = new ConcurrentDictionary<OboeHardwareDeviceSession, byte>();
|
||||
}
|
||||
|
||||
public static bool IsSupported => true;
|
||||
|
||||
public ManualResetEvent GetUpdateRequiredEvent()
|
||||
{
|
||||
return _updateRequiredEvent;
|
||||
}
|
||||
|
||||
public ManualResetEvent GetPauseEvent()
|
||||
{
|
||||
return _pauseEvent;
|
||||
}
|
||||
|
||||
public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount, float volume)
|
||||
{
|
||||
if (channelCount == 0)
|
||||
{
|
||||
channelCount = 2;
|
||||
}
|
||||
|
||||
if (sampleRate == 0)
|
||||
{
|
||||
sampleRate = Constants.TargetSampleRate;
|
||||
}
|
||||
|
||||
if (direction != Direction.Output)
|
||||
{
|
||||
throw new NotImplementedException("Input direction is currently not implemented on Oboe backend!");
|
||||
}
|
||||
|
||||
OboeHardwareDeviceSession session = new OboeHardwareDeviceSession(this, memoryManager, sampleFormat, sampleRate, channelCount, volume);
|
||||
|
||||
_sessions.TryAdd(session, 0);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
foreach (OboeHardwareDeviceSession session in _sessions.Keys)
|
||||
{
|
||||
session.Dispose();
|
||||
}
|
||||
|
||||
_pauseEvent.Dispose();
|
||||
|
||||
_sessions.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public bool SupportsSampleRate(uint sampleRate)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SupportsSampleFormat(SampleFormat sampleFormat)
|
||||
{
|
||||
return sampleFormat != SampleFormat.Adpcm;
|
||||
}
|
||||
|
||||
public bool SupportsChannelCount(uint channelCount)
|
||||
{
|
||||
return channelCount == 1 || channelCount == 2 || channelCount == 4 || channelCount == 6;
|
||||
}
|
||||
|
||||
public bool SupportsDirection(Direction direction)
|
||||
{
|
||||
return direction == Direction.Output;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,189 +0,0 @@
|
||||
using Ryujinx.Audio.Backends.Common;
|
||||
using Ryujinx.Audio.Common;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace LibRyujinx.Shared.Audio.Oboe
|
||||
{
|
||||
internal class OboeHardwareDeviceSession : HardwareDeviceSessionOutputBase
|
||||
{
|
||||
private OboeHardwareDeviceDriver _driver;
|
||||
private bool _isClosed;
|
||||
private bool _isWorkerActive;
|
||||
private Queue<OboeAudioBuffer> _queuedBuffers;
|
||||
private bool _isActive;
|
||||
private ulong _playedSampleCount;
|
||||
private Thread _workerThread;
|
||||
private ManualResetEvent _updateRequiredEvent;
|
||||
private IntPtr _session;
|
||||
private object _queueLock = new object();
|
||||
private object _trackLock = new object();
|
||||
|
||||
public OboeHardwareDeviceSession(OboeHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
|
||||
{
|
||||
_driver = driver;
|
||||
_isActive = false;
|
||||
_playedSampleCount = 0;
|
||||
_isWorkerActive = true;
|
||||
_queuedBuffers = new Queue<OboeAudioBuffer>();
|
||||
_updateRequiredEvent = driver.GetUpdateRequiredEvent();
|
||||
|
||||
_session = OboeInterop.CreateSession((int)requestedSampleFormat, requestedSampleRate, requestedChannelCount);
|
||||
|
||||
_workerThread = new Thread(Update);
|
||||
_workerThread.Name = $"HardwareDeviceSession.Android.Track";
|
||||
_workerThread.Start();
|
||||
|
||||
SetVolume(requestedVolume);
|
||||
}
|
||||
|
||||
public override void UnregisterBuffer(AudioBuffer buffer) { }
|
||||
|
||||
public unsafe void Update(object ignored)
|
||||
{
|
||||
while (_isWorkerActive)
|
||||
{
|
||||
bool needUpdate = false;
|
||||
|
||||
bool hasBuffer;
|
||||
|
||||
OboeAudioBuffer buffer;
|
||||
|
||||
lock (_queueLock)
|
||||
{
|
||||
hasBuffer = _queuedBuffers.TryPeek(out buffer);
|
||||
}
|
||||
|
||||
while (hasBuffer)
|
||||
{
|
||||
StartIfNotPlaying();
|
||||
|
||||
if (_isClosed)
|
||||
break;
|
||||
|
||||
fixed(byte* ptr = buffer.Data)
|
||||
OboeInterop.WriteToSession(_session, (ulong)ptr, buffer.SampleCount);
|
||||
|
||||
lock (_queueLock)
|
||||
{
|
||||
_playedSampleCount += buffer.SampleCount;
|
||||
|
||||
_queuedBuffers.TryDequeue(out _);
|
||||
}
|
||||
|
||||
needUpdate = true;
|
||||
|
||||
lock (_queueLock)
|
||||
{
|
||||
hasBuffer = _queuedBuffers.TryPeek(out buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (needUpdate)
|
||||
{
|
||||
_updateRequiredEvent.Set();
|
||||
}
|
||||
|
||||
// No work
|
||||
Thread.Sleep(5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (_session == 0)
|
||||
return;
|
||||
|
||||
PrepareToClose();
|
||||
|
||||
OboeInterop.CloseSession(_session);
|
||||
|
||||
_session = 0;
|
||||
}
|
||||
|
||||
public override void PrepareToClose()
|
||||
{
|
||||
_isClosed = true;
|
||||
_isWorkerActive = false;
|
||||
_workerThread?.Join();
|
||||
Stop();
|
||||
}
|
||||
|
||||
private void StartIfNotPlaying()
|
||||
{
|
||||
lock (_trackLock)
|
||||
{
|
||||
if (_isClosed)
|
||||
return;
|
||||
|
||||
if (OboeInterop.IsPlaying(_session) == 0)
|
||||
{
|
||||
Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void QueueBuffer(AudioBuffer buffer)
|
||||
{
|
||||
lock (_queueLock)
|
||||
{
|
||||
OboeAudioBuffer driverBuffer = new OboeAudioBuffer(buffer.DataPointer, buffer.Data, GetSampleCount(buffer));
|
||||
|
||||
_queuedBuffers.Enqueue(driverBuffer);
|
||||
|
||||
if (_isActive)
|
||||
{
|
||||
StartIfNotPlaying();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override float GetVolume()
|
||||
{
|
||||
return OboeInterop.GetSessionVolume(_session);
|
||||
}
|
||||
|
||||
public override ulong GetPlayedSampleCount()
|
||||
{
|
||||
lock (_queueLock)
|
||||
{
|
||||
return _playedSampleCount;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetVolume(float volume)
|
||||
{
|
||||
volume = 1;
|
||||
OboeInterop.SetSessionVolume(_session, volume);
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
if (_isClosed)
|
||||
return;
|
||||
|
||||
OboeInterop.StartSession(_session);
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
OboeInterop.StopSession(_session);
|
||||
}
|
||||
|
||||
public override bool WasBufferFullyConsumed(AudioBuffer buffer)
|
||||
{
|
||||
lock (_queueLock)
|
||||
{
|
||||
if (!_queuedBuffers.TryPeek(out OboeAudioBuffer driverBuffer))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return driverBuffer.DriverIdentifier != buffer.DataPointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LibRyujinx.Shared.Audio.Oboe
|
||||
{
|
||||
internal static partial class OboeInterop
|
||||
{
|
||||
private const string InteropLib = "libryujinxjni";
|
||||
|
||||
[LibraryImport(InteropLib, EntryPoint = "create_session")]
|
||||
public static partial IntPtr CreateSession(int sample_format,
|
||||
uint sample_rate,
|
||||
uint channel_count);
|
||||
|
||||
|
||||
[LibraryImport(InteropLib, EntryPoint = "start_session")]
|
||||
public static partial void StartSession(IntPtr session);
|
||||
|
||||
[LibraryImport(InteropLib, EntryPoint = "stop_session")]
|
||||
public static partial void StopSession(IntPtr session);
|
||||
|
||||
[LibraryImport(InteropLib, EntryPoint = "close_session")]
|
||||
public static partial void CloseSession(IntPtr session);
|
||||
|
||||
[LibraryImport(InteropLib, EntryPoint = "set_session_volume")]
|
||||
public static partial void SetSessionVolume(IntPtr session, float volume);
|
||||
|
||||
[LibraryImport(InteropLib, EntryPoint = "get_session_volume")]
|
||||
public static partial float GetSessionVolume(IntPtr session);
|
||||
|
||||
[LibraryImport(InteropLib, EntryPoint = "is_playing")]
|
||||
public static partial int IsPlaying(IntPtr session);
|
||||
|
||||
[LibraryImport(InteropLib, EntryPoint = "write_to_session")]
|
||||
public static partial void WriteToSession(IntPtr session, ulong data, ulong samples);
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@ using LibRyujinx.Jni.Pointers;
|
||||
using LibRyujinx.Jni.Primitives;
|
||||
using LibRyujinx.Jni.References;
|
||||
using LibRyujinx.Jni.Values;
|
||||
using LibRyujinx.Shared.Audio.Oboe;
|
||||
using Rxmxnx.PInvoke;
|
||||
using Ryujinx.Audio.Backends.OpenAL;
|
||||
using Ryujinx.Common;
|
||||
@ -233,8 +232,6 @@ namespace LibRyujinx
|
||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||
var list = GetDlcContentList(GetStoredString(pathPtr), (ulong)(long)titleId);
|
||||
|
||||
debug_break(4);
|
||||
|
||||
return CreateStringArray(jEnv, list);
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#ifndef RYUJINXNATIVE_RYUIJNX_H
|
||||
#define RYUJINXNATIVE_RYUIJNX_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
@ -36,25 +37,38 @@
|
||||
|
||||
#define LoadLib(a) dlopen(a, RTLD_NOW)
|
||||
|
||||
void* _ryujinxNative = NULL;
|
||||
void *_ryujinxNative = NULL;
|
||||
|
||||
class UiHandler {
|
||||
public:
|
||||
void setTitle(long storedTitle);
|
||||
|
||||
void setMessage(long storedMessage);
|
||||
|
||||
void setWatermark(long wm);
|
||||
|
||||
void setType(int t);
|
||||
|
||||
void setMode(int t);
|
||||
|
||||
void setMinLength(int t);
|
||||
|
||||
void setMaxLength(int t);
|
||||
|
||||
void setInitialText(long text);
|
||||
|
||||
void setSubtitle(long text);
|
||||
|
||||
long getTitle();
|
||||
|
||||
long getMessage();
|
||||
|
||||
long getWatermark();
|
||||
|
||||
long getInitialText();
|
||||
|
||||
long getSubtitle();
|
||||
|
||||
int type = 0;
|
||||
int keyboardMode = 0;
|
||||
int min_length = -1;
|
||||
@ -69,11 +83,10 @@ private:
|
||||
};
|
||||
|
||||
// Ryujinx imported functions
|
||||
bool (*initialize)(char*) = NULL;
|
||||
bool (*initialize)(char *) = NULL;
|
||||
|
||||
long _renderingThreadId = 0;
|
||||
long _currentRenderingThreadId = 0;
|
||||
JavaVM* _vm = nullptr;
|
||||
JavaVM *_vm = nullptr;
|
||||
jobject _mainActivity = nullptr;
|
||||
jclass _mainActivityClass = nullptr;
|
||||
string_helper str_helper = string_helper();
|
||||
|
@ -21,21 +21,20 @@
|
||||
#include <chrono>
|
||||
#include <csignal>
|
||||
|
||||
jmethodID _updateFrameTime;
|
||||
JNIEnv* _rendererEnv = nullptr;
|
||||
JNIEnv *_rendererEnv = nullptr;
|
||||
|
||||
std::chrono::time_point<std::chrono::steady_clock, std::chrono::nanoseconds> _currentTimePoint;
|
||||
|
||||
std::string progressInfo = "";
|
||||
float progress = -1;
|
||||
|
||||
JNIEnv* getEnv(bool isRenderer){
|
||||
JNIEnv* env;
|
||||
if(isRenderer){
|
||||
JNIEnv *getEnv(bool isRenderer) {
|
||||
JNIEnv *env;
|
||||
if (isRenderer) {
|
||||
env = _rendererEnv;
|
||||
}
|
||||
|
||||
if(env != nullptr)
|
||||
if (env != nullptr)
|
||||
return env;
|
||||
|
||||
auto result = _vm->AttachCurrentThread(&env, NULL);
|
||||
@ -43,82 +42,82 @@ JNIEnv* getEnv(bool isRenderer){
|
||||
return env;
|
||||
}
|
||||
|
||||
void detachEnv(){
|
||||
void detachEnv() {
|
||||
auto result = _vm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_org_ryujinx_android_NativeHelpers_getNativeWindow(
|
||||
JNIEnv *env,
|
||||
jobject instance,
|
||||
jobject surface) {
|
||||
auto nativeWindow = ANativeWindow_fromSurface(env, surface);
|
||||
return nativeWindow == NULL ? -1 : (jlong) nativeWindow;
|
||||
}
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_org_ryujinx_android_NativeHelpers_getNativeWindow(
|
||||
JNIEnv *env,
|
||||
jobject instance,
|
||||
jobject surface) {
|
||||
auto nativeWindow = ANativeWindow_fromSurface(env, surface);
|
||||
return nativeWindow == NULL ? -1 : (jlong) nativeWindow;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_ryujinx_android_NativeHelpers_releaseNativeWindow(
|
||||
JNIEnv *env,
|
||||
jobject instance,
|
||||
jlong window) {
|
||||
auto nativeWindow = (ANativeWindow *) window;
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_ryujinx_android_NativeHelpers_releaseNativeWindow(
|
||||
JNIEnv *env,
|
||||
jobject instance,
|
||||
jlong window) {
|
||||
auto nativeWindow = (ANativeWindow *) window;
|
||||
|
||||
if (nativeWindow != NULL)
|
||||
ANativeWindow_release(nativeWindow);
|
||||
}
|
||||
if (nativeWindow != NULL)
|
||||
ANativeWindow_release(nativeWindow);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_ryujinx_android_NativeHelpers_attachCurrentThread(
|
||||
JNIEnv *env,
|
||||
jobject instance) {
|
||||
JavaVM* jvm = NULL;
|
||||
env->GetJavaVM(&jvm);
|
||||
JavaVM *jvm = NULL;
|
||||
env->GetJavaVM(&jvm);
|
||||
|
||||
if(jvm != NULL)
|
||||
jvm->AttachCurrentThread(&env, NULL);
|
||||
if (jvm != NULL)
|
||||
jvm->AttachCurrentThread(&env, NULL);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_ryujinx_android_NativeHelpers_detachCurrentThread(
|
||||
JNIEnv *env,
|
||||
jobject instance) {
|
||||
JavaVM* jvm = NULL;
|
||||
JavaVM *jvm = NULL;
|
||||
env->GetJavaVM(&jvm);
|
||||
|
||||
if(jvm != NULL)
|
||||
if (jvm != NULL)
|
||||
jvm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
long createSurface(long native_surface, long instance)
|
||||
{
|
||||
long createSurface(long native_surface, long instance) {
|
||||
auto nativeWindow = (ANativeWindow *) native_surface;
|
||||
VkSurfaceKHR surface;
|
||||
auto vkInstance = (VkInstance)instance;
|
||||
auto vkInstance = (VkInstance) instance;
|
||||
auto fpCreateAndroidSurfaceKHR =
|
||||
reinterpret_cast<PFN_vkCreateAndroidSurfaceKHR>(vkGetInstanceProcAddr(vkInstance, "vkCreateAndroidSurfaceKHR"));
|
||||
reinterpret_cast<PFN_vkCreateAndroidSurfaceKHR>(vkGetInstanceProcAddr(vkInstance,
|
||||
"vkCreateAndroidSurfaceKHR"));
|
||||
if (!fpCreateAndroidSurfaceKHR)
|
||||
return -1;
|
||||
VkAndroidSurfaceCreateInfoKHR info = { VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR };
|
||||
VkAndroidSurfaceCreateInfoKHR info = {VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR};
|
||||
info.window = nativeWindow;
|
||||
VK_CHECK(fpCreateAndroidSurfaceKHR(vkInstance, &info, nullptr, &surface));
|
||||
return (long)surface;
|
||||
return (long) surface;
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_org_ryujinx_android_NativeHelpers_getCreateSurfacePtr(
|
||||
JNIEnv *env,
|
||||
jobject instance) {
|
||||
return (jlong)createSurface;
|
||||
return (jlong) createSurface;
|
||||
}
|
||||
|
||||
char* getStringPointer(
|
||||
char *getStringPointer(
|
||||
JNIEnv *env,
|
||||
jstring jS) {
|
||||
const char *cparam = env->GetStringUTFChars(jS, 0);
|
||||
auto len = env->GetStringUTFLength(jS);
|
||||
char* s= new char[len];
|
||||
char *s = new char[len];
|
||||
strcpy(s, cparam);
|
||||
env->ReleaseStringUTFChars(jS, cparam);
|
||||
|
||||
@ -127,7 +126,7 @@ char* getStringPointer(
|
||||
|
||||
jstring createString(
|
||||
JNIEnv *env,
|
||||
char* ch) {
|
||||
char *ch) {
|
||||
auto str = env->NewStringUTF(ch);
|
||||
|
||||
return str;
|
||||
@ -144,15 +143,9 @@ jstring createStringFromStdString(
|
||||
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_org_ryujinx_android_MainActivity_getRenderingThreadId(JNIEnv *env, jobject thiz) {
|
||||
return _currentRenderingThreadId;
|
||||
}
|
||||
extern "C"
|
||||
void setRenderingThread(){
|
||||
void setRenderingThread() {
|
||||
auto currentId = pthread_self();
|
||||
|
||||
_currentRenderingThreadId = currentId;
|
||||
_renderingThreadId = currentId;
|
||||
|
||||
_currentTimePoint = std::chrono::high_resolution_clock::now();
|
||||
@ -160,7 +153,7 @@ void setRenderingThread(){
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_ryujinx_android_MainActivity_initVm(JNIEnv *env, jobject thiz) {
|
||||
JavaVM* vm = nullptr;
|
||||
JavaVM *vm = nullptr;
|
||||
auto success = env->GetJavaVM(&vm);
|
||||
_vm = vm;
|
||||
_mainActivity = thiz;
|
||||
@ -171,25 +164,26 @@ 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");
|
||||
jmethodID frameEnd = env->GetStaticMethodID(cl, "frameEnded", "(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,
|
||||
env->CallStaticVoidMethod(cl, frameEnd,
|
||||
nano);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void setProgressInfo(char* info, float progressValue) {
|
||||
progressInfo = std::string (info);
|
||||
void setProgressInfo(char *info, float progressValue) {
|
||||
progressInfo = std::string(info);
|
||||
progress = progressValue;
|
||||
}
|
||||
|
||||
bool isInitialOrientationFlipped = true;
|
||||
|
||||
extern "C"
|
||||
void setCurrentTransform(long native_window, int transform){
|
||||
if(native_window == 0 || native_window == -1)
|
||||
void setCurrentTransform(long native_window, int transform) {
|
||||
if (native_window == 0 || native_window == -1)
|
||||
return;
|
||||
auto nativeWindow = (ANativeWindow *) native_window;
|
||||
|
||||
@ -203,10 +197,12 @@ void setCurrentTransform(long native_window, int transform){
|
||||
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_IDENTITY;
|
||||
break;
|
||||
case 0x2:
|
||||
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_ROTATE_90;
|
||||
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_ROTATE_90;
|
||||
break;
|
||||
case 0x4:
|
||||
nativeTransform = isInitialOrientationFlipped ? ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_IDENTITY : ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_ROTATE_180;
|
||||
nativeTransform = isInitialOrientationFlipped
|
||||
? ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_IDENTITY
|
||||
: ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_ROTATE_180;
|
||||
break;
|
||||
case 0x8:
|
||||
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_ROTATE_270;
|
||||
@ -232,7 +228,8 @@ void setCurrentTransform(long native_window, int transform){
|
||||
break;
|
||||
}
|
||||
|
||||
nativeWindow->perform(nativeWindow, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM, static_cast<int32_t>(nativeTransform));
|
||||
nativeWindow->perform(nativeWindow, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
|
||||
static_cast<int32_t>(nativeTransform));
|
||||
}
|
||||
|
||||
extern "C"
|
||||
@ -254,19 +251,19 @@ Java_org_ryujinx_android_NativeHelpers_loadDriver(JNIEnv *env, jobject thiz,
|
||||
driverName,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
);
|
||||
|
||||
delete libPath;
|
||||
delete privateAppsPath;
|
||||
delete driverName;
|
||||
|
||||
return (jlong)handle;
|
||||
return (jlong) handle;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void debug_break(int code){
|
||||
if(code >= 3)
|
||||
int r = 0;
|
||||
void debug_break(int code) {
|
||||
if (code >= 3)
|
||||
int r = 0;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
@ -278,7 +275,7 @@ Java_org_ryujinx_android_NativeHelpers_setTurboMode(JNIEnv *env, jobject thiz, j
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_org_ryujinx_android_NativeHelpers_getMaxSwapInterval(JNIEnv *env, jobject thiz,
|
||||
jlong native_window) {
|
||||
jlong native_window) {
|
||||
auto nativeWindow = (ANativeWindow *) native_window;
|
||||
|
||||
return nativeWindow->maxSwapInterval;
|
||||
@ -315,14 +312,14 @@ Java_org_ryujinx_android_NativeHelpers_getProgressInfo(JNIEnv *env, jobject thiz
|
||||
}
|
||||
|
||||
extern "C"
|
||||
long storeString(char* str){
|
||||
long storeString(char *str) {
|
||||
return str_helper.store_cstring(str);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* getString(long id){
|
||||
const char *getString(long id) {
|
||||
auto str = str_helper.get_stored(id);
|
||||
auto cstr = (char*)::malloc(str.length() + 1);
|
||||
auto cstr = (char *) ::malloc(str.length() + 1);
|
||||
::strcpy(cstr, str.c_str());
|
||||
return cstr;
|
||||
}
|
||||
@ -381,7 +378,7 @@ Java_org_ryujinx_android_NativeHelpers_setIsInitialOrientationFlipped(JNIEnv *en
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_org_ryujinx_android_NativeHelpers_getUiHandlerRequestType(JNIEnv *env, jobject thiz) {
|
||||
return ui_handler.type;
|
||||
return ui_handler.type;
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jlong JNICALL
|
||||
@ -396,7 +393,7 @@ Java_org_ryujinx_android_NativeHelpers_getUiHandlerRequestMessage(JNIEnv *env, j
|
||||
|
||||
|
||||
void UiHandler::setTitle(long storedTitle) {
|
||||
if(title != -1){
|
||||
if (title != -1) {
|
||||
str_helper.get_stored(title);
|
||||
title = -1;
|
||||
}
|
||||
@ -405,7 +402,7 @@ void UiHandler::setTitle(long storedTitle) {
|
||||
}
|
||||
|
||||
void UiHandler::setMessage(long storedMessage) {
|
||||
if(message != -1){
|
||||
if (message != -1) {
|
||||
str_helper.get_stored(message);
|
||||
message = -1;
|
||||
}
|
||||
@ -430,7 +427,7 @@ long UiHandler::getMessage() {
|
||||
}
|
||||
|
||||
void UiHandler::setWatermark(long wm) {
|
||||
if(watermark != -1){
|
||||
if (watermark != -1) {
|
||||
str_helper.get_stored(watermark);
|
||||
watermark = -1;
|
||||
}
|
||||
@ -453,7 +450,7 @@ long UiHandler::getWatermark() {
|
||||
}
|
||||
|
||||
void UiHandler::setInitialText(long text) {
|
||||
if(initialText != -1){
|
||||
if (initialText != -1) {
|
||||
str_helper.get_stored(watermark);
|
||||
initialText = -1;
|
||||
}
|
||||
@ -462,7 +459,7 @@ void UiHandler::setInitialText(long text) {
|
||||
}
|
||||
|
||||
void UiHandler::setSubtitle(long text) {
|
||||
if(subtitle != -1){
|
||||
if (subtitle != -1) {
|
||||
str_helper.get_stored(subtitle);
|
||||
subtitle = -1;
|
||||
}
|
||||
@ -489,12 +486,12 @@ void UiHandler::setMode(int t) {
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_org_ryujinx_android_NativeHelpers_getUiHandlerMinLength(JNIEnv *env, jobject thiz) {
|
||||
return ui_handler.min_length;
|
||||
return ui_handler.min_length;
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_org_ryujinx_android_NativeHelpers_getUiHandlerMaxLength(JNIEnv *env, jobject thiz) {
|
||||
return ui_handler.max_length;
|
||||
return ui_handler.max_length;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
|
@ -2,7 +2,6 @@ package org.ryujinx.android
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.view.SurfaceHolder
|
||||
import android.view.SurfaceView
|
||||
import androidx.compose.runtime.MutableState
|
||||
@ -130,7 +129,8 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
|
||||
if (c >= 1000) {
|
||||
if (helper.getProgressValue() == -1f)
|
||||
progress?.apply {
|
||||
this.value = "Loading ${if(mainViewModel.isMiiEditorLaunched) "Mii Editor" else game!!.titleName}"
|
||||
this.value =
|
||||
"Loading ${if (mainViewModel.isMiiEditorLaunched) "Mii Editor" else game!!.titleName}"
|
||||
}
|
||||
c = 0
|
||||
mainViewModel.updateStats(
|
||||
@ -144,26 +144,6 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
|
||||
}
|
||||
|
||||
private fun runGame() {
|
||||
// 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)
|
||||
val newthreadId = mainViewModel.activity.getRenderingThreadId()
|
||||
|
||||
if (threadId != newthreadId) {
|
||||
mainViewModel.performanceManager?.closeCurrentRenderingSession()
|
||||
}
|
||||
threadId = newthreadId
|
||||
if (threadId != 0L) {
|
||||
mainViewModel.performanceManager?.initializeRenderingSession(threadId)
|
||||
}
|
||||
}
|
||||
mainViewModel.performanceManager?.closeCurrentRenderingSession()
|
||||
}
|
||||
}
|
||||
|
||||
thread {
|
||||
mainViewModel.activity.uiHandler.listen()
|
||||
|
@ -1,9 +1,7 @@
|
||||
package org.ryujinx.android
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.view.KeyEvent
|
||||
@ -22,7 +20,6 @@ import org.ryujinx.android.ui.theme.RyujinxAndroidTheme
|
||||
import org.ryujinx.android.viewmodels.MainViewModel
|
||||
import org.ryujinx.android.viewmodels.QuickSettings
|
||||
import org.ryujinx.android.views.MainView
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
class MainActivity : BaseActivity() {
|
||||
@ -31,24 +28,23 @@ class MainActivity : BaseActivity() {
|
||||
private lateinit var motionSensorManager: MotionSensorManager
|
||||
private var _isInit: Boolean = false
|
||||
var isGameRunning = false
|
||||
var isActive = false
|
||||
var storageHelper: SimpleStorageHelper? = null
|
||||
lateinit var uiHandler: UiHandler
|
||||
|
||||
companion object {
|
||||
var mainViewModel: MainViewModel? = null
|
||||
var AppPath : String = ""
|
||||
var AppPath: String = ""
|
||||
var StorageHelper: SimpleStorageHelper? = null
|
||||
val performanceMonitor = PerformanceMonitor()
|
||||
|
||||
@JvmStatic
|
||||
fun updateRenderSessionPerformance(gameTime : Long)
|
||||
{
|
||||
if(gameTime <= 0)
|
||||
return
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
mainViewModel?.performanceManager?.updateRenderingSessionTime(gameTime)
|
||||
fun frameEnded(gameTime: Long) {
|
||||
mainViewModel?.activity?.apply {
|
||||
if (isActive && QuickSettings(this).enablePerformanceMode) {
|
||||
mainViewModel?.performanceManager?.setTurboMode(true);
|
||||
}
|
||||
}
|
||||
|
||||
mainViewModel?.gameHost?.hideProgressIndicator()
|
||||
}
|
||||
}
|
||||
@ -60,7 +56,6 @@ class MainActivity : BaseActivity() {
|
||||
initVm()
|
||||
}
|
||||
|
||||
external fun getRenderingThreadId() : Long
|
||||
private external fun initVm()
|
||||
|
||||
private fun initialize() {
|
||||
@ -70,26 +65,52 @@ class MainActivity : BaseActivity() {
|
||||
val appPath: String = AppPath
|
||||
|
||||
var quickSettings = QuickSettings(this)
|
||||
RyujinxNative.instance.loggingSetEnabled(LogLevel.Debug.ordinal, quickSettings.enableDebugLogs)
|
||||
RyujinxNative.instance.loggingSetEnabled(LogLevel.Info.ordinal, quickSettings.enableInfoLogs)
|
||||
RyujinxNative.instance.loggingSetEnabled(LogLevel.Stub.ordinal, quickSettings.enableStubLogs)
|
||||
RyujinxNative.instance.loggingSetEnabled(LogLevel.Warning.ordinal, quickSettings.enableWarningLogs)
|
||||
RyujinxNative.instance.loggingSetEnabled(LogLevel.Error.ordinal, quickSettings.enableErrorLogs)
|
||||
RyujinxNative.instance.loggingSetEnabled(LogLevel.AccessLog.ordinal, quickSettings.enableAccessLogs)
|
||||
RyujinxNative.instance.loggingSetEnabled(LogLevel.Guest.ordinal, quickSettings.enableGuestLogs)
|
||||
RyujinxNative.instance.loggingSetEnabled(LogLevel.Trace.ordinal, quickSettings.enableTraceLogs)
|
||||
val success = RyujinxNative.instance.initialize(NativeHelpers.instance.storeStringJava(appPath))
|
||||
RyujinxNative.instance.loggingSetEnabled(
|
||||
LogLevel.Debug.ordinal,
|
||||
quickSettings.enableDebugLogs
|
||||
)
|
||||
RyujinxNative.instance.loggingSetEnabled(
|
||||
LogLevel.Info.ordinal,
|
||||
quickSettings.enableInfoLogs
|
||||
)
|
||||
RyujinxNative.instance.loggingSetEnabled(
|
||||
LogLevel.Stub.ordinal,
|
||||
quickSettings.enableStubLogs
|
||||
)
|
||||
RyujinxNative.instance.loggingSetEnabled(
|
||||
LogLevel.Warning.ordinal,
|
||||
quickSettings.enableWarningLogs
|
||||
)
|
||||
RyujinxNative.instance.loggingSetEnabled(
|
||||
LogLevel.Error.ordinal,
|
||||
quickSettings.enableErrorLogs
|
||||
)
|
||||
RyujinxNative.instance.loggingSetEnabled(
|
||||
LogLevel.AccessLog.ordinal,
|
||||
quickSettings.enableAccessLogs
|
||||
)
|
||||
RyujinxNative.instance.loggingSetEnabled(
|
||||
LogLevel.Guest.ordinal,
|
||||
quickSettings.enableGuestLogs
|
||||
)
|
||||
RyujinxNative.instance.loggingSetEnabled(
|
||||
LogLevel.Trace.ordinal,
|
||||
quickSettings.enableTraceLogs
|
||||
)
|
||||
val success =
|
||||
RyujinxNative.instance.initialize(NativeHelpers.instance.storeStringJava(appPath))
|
||||
|
||||
uiHandler = UiHandler()
|
||||
_isInit = success
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
motionSensorManager = MotionSensorManager(this)
|
||||
Thread.setDefaultUncaughtExceptionHandler(crashHandler)
|
||||
|
||||
if(
|
||||
if (
|
||||
!Environment.isExternalStorageManager()
|
||||
) {
|
||||
storageHelper?.storage?.requestFullStorageAccess()
|
||||
@ -99,8 +120,9 @@ class MainActivity : BaseActivity() {
|
||||
|
||||
initialize()
|
||||
|
||||
window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
||||
WindowCompat.setDecorFitsSystemWindows(window,false)
|
||||
window.attributes.layoutInDisplayCutoutMode =
|
||||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
|
||||
mainViewModel = MainViewModel(this)
|
||||
mainViewModel!!.physicalControllerManager = physicalControllerManager
|
||||
@ -133,25 +155,6 @@ class MainActivity : BaseActivity() {
|
||||
storageHelper?.onRestoreInstanceState(savedInstanceState)
|
||||
}
|
||||
|
||||
// Game Stuff
|
||||
private fun force60HzRefreshRate(enable: Boolean) {
|
||||
// Hack for MIUI devices since they don't support the standard Android APIs
|
||||
try {
|
||||
val setFpsIntent = Intent("com.miui.powerkeeper.SET_ACTIVITY_FPS")
|
||||
setFpsIntent.putExtra("package_name", "org.ryujinx.android")
|
||||
setFpsIntent.putExtra("isEnter", enable)
|
||||
sendBroadcast(setFpsIntent)
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
|
||||
if (enable)
|
||||
display?.supportedModes?.minByOrNull { abs(it.refreshRate - 60f) }
|
||||
?.let { window.attributes.preferredDisplayModeId = it.modeId }
|
||||
else
|
||||
display?.supportedModes?.maxByOrNull { it.refreshRate }
|
||||
?.let { window.attributes.preferredDisplayModeId = it.modeId }
|
||||
}
|
||||
|
||||
fun setFullScreen(fullscreen: Boolean) {
|
||||
requestedOrientation =
|
||||
if (fullscreen) ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE else ActivityInfo.SCREEN_ORIENTATION_FULL_USER
|
||||
@ -190,20 +193,19 @@ class MainActivity : BaseActivity() {
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
isActive = false
|
||||
|
||||
if(isGameRunning) {
|
||||
NativeHelpers.instance.setTurboMode(false)
|
||||
force60HzRefreshRate(false)
|
||||
if (isGameRunning) {
|
||||
mainViewModel?.performanceManager?.setTurboMode(false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
isActive = true
|
||||
|
||||
if(isGameRunning) {
|
||||
if (isGameRunning) {
|
||||
setFullScreen(true)
|
||||
NativeHelpers.instance.setTurboMode(true)
|
||||
force60HzRefreshRate(true)
|
||||
if (QuickSettings(this).enableMotion)
|
||||
motionSensorManager.register()
|
||||
}
|
||||
@ -211,10 +213,10 @@ class MainActivity : BaseActivity() {
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
isActive = true
|
||||
|
||||
if(isGameRunning) {
|
||||
NativeHelpers.instance.setTurboMode(false)
|
||||
force60HzRefreshRate(false)
|
||||
if (isGameRunning) {
|
||||
mainViewModel?.performanceManager?.setTurboMode(false)
|
||||
}
|
||||
|
||||
motionSensorManager.unregister()
|
||||
|
@ -1,49 +1,31 @@
|
||||
package org.ryujinx.android
|
||||
|
||||
import android.os.Build
|
||||
import android.os.PerformanceHintManager
|
||||
import androidx.annotation.RequiresApi
|
||||
import android.content.Intent
|
||||
import kotlin.math.abs
|
||||
|
||||
class PerformanceManager(private val performanceHintManager: PerformanceHintManager) {
|
||||
private var _isEnabled: Boolean = false
|
||||
private var renderingSession: PerformanceHintManager.Session? = null
|
||||
private val DEFAULT_TARGET_NS = 16666666L
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.S)
|
||||
fun initializeRenderingSession(threadId : Long){
|
||||
if(!_isEnabled || renderingSession != null)
|
||||
return
|
||||
|
||||
val 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()
|
||||
class PerformanceManager(private val activity: MainActivity) {
|
||||
companion object {
|
||||
fun force60HzRefreshRate(enable: Boolean, activity: MainActivity) {
|
||||
// Hack for MIUI devices since they don't support the standard Android APIs
|
||||
try {
|
||||
val setFpsIntent = Intent("com.miui.powerkeeper.SET_ACTIVITY_FPS")
|
||||
setFpsIntent.putExtra("package_name", "org.ryujinx.android")
|
||||
setFpsIntent.putExtra("isEnter", enable)
|
||||
activity.sendBroadcast(setFpsIntent)
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if (enable)
|
||||
activity.display?.supportedModes?.minByOrNull { abs(it.refreshRate - 60f) }
|
||||
?.let { activity.window.attributes.preferredDisplayModeId = it.modeId }
|
||||
else
|
||||
activity.display?.supportedModes?.maxByOrNull { it.refreshRate }
|
||||
?.let { activity.window.attributes.preferredDisplayModeId = it.modeId }
|
||||
}
|
||||
}
|
||||
|
||||
fun setTurboMode(enable: Boolean) {
|
||||
NativeHelpers.instance.setTurboMode(enable)
|
||||
force60HzRefreshRate(enable, activity)
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,6 @@
|
||||
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 com.anggrayudi.storage.extension.launchOnUiThread
|
||||
@ -49,16 +46,12 @@ class MainViewModel(val activity: MainActivity) {
|
||||
field = value
|
||||
field?.setProgressStates(showLoading, progressValue, progress)
|
||||
}
|
||||
var navController : NavHostController? = null
|
||||
var navController: NavHostController? = null
|
||||
|
||||
var homeViewModel: HomeViewModel = HomeViewModel(activity, this)
|
||||
|
||||
init {
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val hintService =
|
||||
activity.getSystemService(Context.PERFORMANCE_HINT_SERVICE) as PerformanceHintManager
|
||||
performanceManager = PerformanceManager(hintService)
|
||||
}
|
||||
performanceManager = PerformanceManager(activity)
|
||||
}
|
||||
|
||||
fun closeGame() {
|
||||
@ -70,14 +63,14 @@ class MainViewModel(val activity: MainActivity) {
|
||||
motionSensorManager?.setControllerId(-1)
|
||||
}
|
||||
|
||||
fun refreshFirmwareVersion(){
|
||||
fun refreshFirmwareVersion() {
|
||||
var handle = RyujinxNative.instance.deviceGetInstalledFirmwareVersion()
|
||||
if(handle != -1L) {
|
||||
if (handle != -1L) {
|
||||
firmwareVersion = NativeHelpers.instance.getStringJava(handle)
|
||||
}
|
||||
}
|
||||
|
||||
fun loadGame(game:GameModel) : Boolean {
|
||||
fun loadGame(game: GameModel): Boolean {
|
||||
val nativeRyujinx = RyujinxNative.instance
|
||||
|
||||
val descriptor = game.open()
|
||||
@ -188,7 +181,7 @@ class MainViewModel(val activity: MainActivity) {
|
||||
return true
|
||||
}
|
||||
|
||||
fun loadMiiEditor() : Boolean {
|
||||
fun loadMiiEditor(): Boolean {
|
||||
val nativeRyujinx = RyujinxNative.instance
|
||||
|
||||
gameModel = null
|
||||
@ -292,42 +285,42 @@ class MainViewModel(val activity: MainActivity) {
|
||||
return true
|
||||
}
|
||||
|
||||
fun clearPptcCache(titleId :String){
|
||||
if(titleId.isNotEmpty()){
|
||||
fun clearPptcCache(titleId: String) {
|
||||
if (titleId.isNotEmpty()) {
|
||||
val basePath = MainActivity.AppPath + "/games/$titleId/cache/cpu"
|
||||
if(File(basePath).exists()){
|
||||
if (File(basePath).exists()) {
|
||||
var caches = mutableListOf<String>()
|
||||
|
||||
val mainCache = basePath + "${File.separator}0"
|
||||
File(mainCache).listFiles()?.forEach {
|
||||
if(it.isFile && it.name.endsWith(".cache"))
|
||||
if (it.isFile && it.name.endsWith(".cache"))
|
||||
caches.add(it.absolutePath)
|
||||
}
|
||||
val backupCache = basePath + "${File.separator}1"
|
||||
File(backupCache).listFiles()?.forEach {
|
||||
if(it.isFile && it.name.endsWith(".cache"))
|
||||
if (it.isFile && it.name.endsWith(".cache"))
|
||||
caches.add(it.absolutePath)
|
||||
}
|
||||
for(path in caches)
|
||||
for (path in caches)
|
||||
File(path).delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun purgeShaderCache(titleId :String) {
|
||||
if(titleId.isNotEmpty()){
|
||||
fun purgeShaderCache(titleId: String) {
|
||||
if (titleId.isNotEmpty()) {
|
||||
val basePath = MainActivity.AppPath + "/games/$titleId/cache/shader"
|
||||
if(File(basePath).exists()){
|
||||
if (File(basePath).exists()) {
|
||||
var caches = mutableListOf<String>()
|
||||
File(basePath).listFiles()?.forEach {
|
||||
if(!it.isFile)
|
||||
if (!it.isFile)
|
||||
it.delete()
|
||||
else{
|
||||
if(it.name.endsWith(".toc") || it.name.endsWith(".data"))
|
||||
else {
|
||||
if (it.name.endsWith(".toc") || it.name.endsWith(".data"))
|
||||
caches.add(it.absolutePath)
|
||||
}
|
||||
}
|
||||
for(path in caches)
|
||||
for (path in caches)
|
||||
File(path).delete()
|
||||
}
|
||||
}
|
||||
@ -347,7 +340,7 @@ class MainViewModel(val activity: MainActivity) {
|
||||
fifo: Double,
|
||||
gameFps: Double,
|
||||
gameTime: Double
|
||||
){
|
||||
) {
|
||||
fifoState?.apply {
|
||||
this.value = fifo
|
||||
}
|
||||
|
@ -14,10 +14,11 @@ class QuickSettings(val activity: Activity) {
|
||||
var isHostMapped: Boolean
|
||||
var enableShaderCache: Boolean
|
||||
var enableTextureRecompression: Boolean
|
||||
var resScale : Float
|
||||
var isGrid : Boolean
|
||||
var useSwitchLayout : Boolean
|
||||
var enableMotion : Boolean
|
||||
var resScale: Float
|
||||
var isGrid: Boolean
|
||||
var useSwitchLayout: Boolean
|
||||
var enableMotion: Boolean
|
||||
var enablePerformanceMode: Boolean
|
||||
|
||||
// Logs
|
||||
var enableDebugLogs: Boolean
|
||||
@ -29,7 +30,8 @@ class QuickSettings(val activity: Activity) {
|
||||
var enableAccessLogs: Boolean
|
||||
var enableTraceLogs: Boolean
|
||||
|
||||
private var sharedPref: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||
private var sharedPref: SharedPreferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(activity)
|
||||
|
||||
init {
|
||||
isHostMapped = sharedPref.getBoolean("isHostMapped", true)
|
||||
@ -45,6 +47,7 @@ class QuickSettings(val activity: Activity) {
|
||||
isGrid = sharedPref.getBoolean("isGrid", true)
|
||||
useSwitchLayout = sharedPref.getBoolean("useSwitchLayout", true)
|
||||
enableMotion = sharedPref.getBoolean("enableMotion", true)
|
||||
enablePerformanceMode = sharedPref.getBoolean("enablePerformanceMode", true)
|
||||
|
||||
enableDebugLogs = sharedPref.getBoolean("enableDebugLogs", false)
|
||||
enableStubLogs = sharedPref.getBoolean("enableStubLogs", false)
|
||||
@ -56,7 +59,7 @@ class QuickSettings(val activity: Activity) {
|
||||
enableTraceLogs = sharedPref.getBoolean("enableStubLogs", false)
|
||||
}
|
||||
|
||||
fun save(){
|
||||
fun save() {
|
||||
val editor = sharedPref.edit()
|
||||
|
||||
editor.putBoolean("isHostMapped", isHostMapped)
|
||||
@ -72,6 +75,7 @@ class QuickSettings(val activity: Activity) {
|
||||
editor.putBoolean("isGrid", isGrid)
|
||||
editor.putBoolean("useSwitchLayout", useSwitchLayout)
|
||||
editor.putBoolean("enableMotion", enableMotion)
|
||||
editor.putBoolean("enablePerformanceMode", enablePerformanceMode)
|
||||
|
||||
editor.putBoolean("enableDebugLogs", enableDebugLogs)
|
||||
editor.putBoolean("enableStubLogs", enableStubLogs)
|
||||
|
@ -56,6 +56,7 @@ class SettingsViewModel(var navController: NavHostController, val activity: Main
|
||||
isGrid: MutableState<Boolean>,
|
||||
useSwitchLayout: MutableState<Boolean>,
|
||||
enableMotion: MutableState<Boolean>,
|
||||
enablePerformanceMode: MutableState<Boolean>,
|
||||
enableDebugLogs: MutableState<Boolean>,
|
||||
enableStubLogs: MutableState<Boolean>,
|
||||
enableInfoLogs: MutableState<Boolean>,
|
||||
@ -80,6 +81,7 @@ class SettingsViewModel(var navController: NavHostController, val activity: Main
|
||||
isGrid.value = sharedPref.getBoolean("isGrid", true)
|
||||
useSwitchLayout.value = sharedPref.getBoolean("useSwitchLayout", true)
|
||||
enableMotion.value = sharedPref.getBoolean("enableMotion", true)
|
||||
enablePerformanceMode.value = sharedPref.getBoolean("enablePerformanceMode", false)
|
||||
|
||||
enableDebugLogs.value = sharedPref.getBoolean("enableDebugLogs", false)
|
||||
enableStubLogs.value = sharedPref.getBoolean("enableStubLogs", false)
|
||||
@ -105,6 +107,7 @@ class SettingsViewModel(var navController: NavHostController, val activity: Main
|
||||
isGrid: MutableState<Boolean>,
|
||||
useSwitchLayout: MutableState<Boolean>,
|
||||
enableMotion: MutableState<Boolean>,
|
||||
enablePerformanceMode: MutableState<Boolean>,
|
||||
enableDebugLogs: MutableState<Boolean>,
|
||||
enableStubLogs: MutableState<Boolean>,
|
||||
enableInfoLogs: MutableState<Boolean>,
|
||||
@ -129,6 +132,7 @@ class SettingsViewModel(var navController: NavHostController, val activity: Main
|
||||
editor.putBoolean("isGrid", isGrid.value)
|
||||
editor.putBoolean("useSwitchLayout", useSwitchLayout.value)
|
||||
editor.putBoolean("enableMotion", enableMotion.value)
|
||||
editor.putBoolean("enablePerformanceMode", enablePerformanceMode.value)
|
||||
|
||||
editor.putBoolean("enableDebugLogs", enableDebugLogs.value)
|
||||
editor.putBoolean("enableStubLogs", enableStubLogs.value)
|
||||
@ -255,7 +259,7 @@ class SettingsViewModel(var navController: NavHostController, val activity: Main
|
||||
}
|
||||
}
|
||||
|
||||
fun clearFirmwareSelection(installState: MutableState<FirmwareInstallState>){
|
||||
fun clearFirmwareSelection(installState: MutableState<FirmwareInstallState>) {
|
||||
selectedFirmwareFile = null
|
||||
selectedFirmwareVersion = ""
|
||||
installState.value = FirmwareInstallState.None
|
||||
@ -263,7 +267,7 @@ class SettingsViewModel(var navController: NavHostController, val activity: Main
|
||||
}
|
||||
|
||||
|
||||
enum class FirmwareInstallState{
|
||||
enum class FirmwareInstallState {
|
||||
None,
|
||||
Cancelled,
|
||||
Verifying,
|
||||
|
@ -57,6 +57,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import com.anggrayudi.storage.file.extension
|
||||
import org.ryujinx.android.Helpers
|
||||
@ -122,6 +123,7 @@ class SettingViews {
|
||||
val isGrid = remember { mutableStateOf(true) }
|
||||
val useSwitchLayout = remember { mutableStateOf(true) }
|
||||
val enableMotion = remember { mutableStateOf(true) }
|
||||
val enablePerformanceMode = remember { mutableStateOf(true) }
|
||||
|
||||
val enableDebugLogs = remember { mutableStateOf(true) }
|
||||
val enableStubLogs = remember { mutableStateOf(true) }
|
||||
@ -144,6 +146,7 @@ class SettingViews {
|
||||
isGrid,
|
||||
useSwitchLayout,
|
||||
enableMotion,
|
||||
enablePerformanceMode,
|
||||
enableDebugLogs,
|
||||
enableStubLogs,
|
||||
enableInfoLogs,
|
||||
@ -177,6 +180,7 @@ class SettingViews {
|
||||
isGrid,
|
||||
useSwitchLayout,
|
||||
enableMotion,
|
||||
enablePerformanceMode,
|
||||
enableDebugLogs,
|
||||
enableStubLogs,
|
||||
enableInfoLogs,
|
||||
@ -192,9 +196,11 @@ class SettingViews {
|
||||
}
|
||||
})
|
||||
}) { contentPadding ->
|
||||
Column(modifier = Modifier
|
||||
.padding(contentPadding)
|
||||
.verticalScroll(rememberScrollState())) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(contentPadding)
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
ExpandableView(onCardArrowClick = { }, title = "App") {
|
||||
Column(modifier = Modifier.fillMaxWidth()) {
|
||||
Row(
|
||||
@ -303,9 +309,9 @@ class SettingViews {
|
||||
}
|
||||
}
|
||||
|
||||
if(showFirwmareDialog.value) {
|
||||
if (showFirwmareDialog.value) {
|
||||
AlertDialog(onDismissRequest = {
|
||||
if(firmwareInstallState.value != FirmwareInstallState.Install) {
|
||||
if (firmwareInstallState.value != FirmwareInstallState.Install) {
|
||||
showFirwmareDialog.value = false
|
||||
settingsViewModel.clearFirmwareSelection(firmwareInstallState)
|
||||
}
|
||||
@ -327,7 +333,8 @@ class SettingViews {
|
||||
Text(text = "Select a zip or XCI file to install from.")
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.End,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 4.dp)
|
||||
) {
|
||||
Button(onClick = {
|
||||
@ -350,7 +357,8 @@ class SettingViews {
|
||||
Text(text = "Firmware ${settingsViewModel.selectedFirmwareVersion} will be installed. Do you want to continue?")
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.End,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 4.dp)
|
||||
) {
|
||||
Button(onClick = {
|
||||
@ -358,9 +366,11 @@ class SettingViews {
|
||||
firmwareInstallState
|
||||
)
|
||||
|
||||
if(firmwareInstallState.value == FirmwareInstallState.None){
|
||||
if (firmwareInstallState.value == FirmwareInstallState.None) {
|
||||
showFirwmareDialog.value = false
|
||||
settingsViewModel.clearFirmwareSelection(firmwareInstallState)
|
||||
settingsViewModel.clearFirmwareSelection(
|
||||
firmwareInstallState
|
||||
)
|
||||
}
|
||||
}, modifier = Modifier.padding(horizontal = 8.dp)) {
|
||||
Text(text = "Yes")
|
||||
@ -376,34 +386,32 @@ class SettingViews {
|
||||
}
|
||||
} else if (firmwareInstallState.value == FirmwareInstallState.Install) {
|
||||
Text(text = "Installing Firmware ${settingsViewModel.selectedFirmwareVersion}...")
|
||||
LinearProgressIndicator(modifier = Modifier
|
||||
.padding(top = 4.dp))
|
||||
LinearProgressIndicator(
|
||||
modifier = Modifier
|
||||
.padding(top = 4.dp)
|
||||
)
|
||||
} else if (firmwareInstallState.value == FirmwareInstallState.Verifying) {
|
||||
Text(text = "Verifying selected file...")
|
||||
LinearProgressIndicator(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
else if (firmwareInstallState.value == FirmwareInstallState.Done) {
|
||||
LinearProgressIndicator(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
)
|
||||
} else if (firmwareInstallState.value == FirmwareInstallState.Done) {
|
||||
Text(text = "Installed Firmware ${settingsViewModel.selectedFirmwareVersion}")
|
||||
firmwareVersion.value = mainViewModel.firmwareVersion
|
||||
}
|
||||
else if(firmwareInstallState.value == FirmwareInstallState.Cancelled){
|
||||
} else if (firmwareInstallState.value == FirmwareInstallState.Cancelled) {
|
||||
val file = settingsViewModel.selectedFirmwareFile
|
||||
if(file != null){
|
||||
if(file.extension == "xci" || file.extension == "zip"){
|
||||
if(settingsViewModel.selectedFirmwareVersion.isEmpty()) {
|
||||
if (file != null) {
|
||||
if (file.extension == "xci" || file.extension == "zip") {
|
||||
if (settingsViewModel.selectedFirmwareVersion.isEmpty()) {
|
||||
Text(text = "Unable to find version in selected file")
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Text(text = "Unknown Error has occurred. Please check logs")
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Text(text = "File type is not supported")
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Text(text = "File type is not supported")
|
||||
}
|
||||
}
|
||||
@ -503,6 +511,32 @@ class SettingViews {
|
||||
ignoreMissingServices.value = !ignoreMissingServices.value
|
||||
})
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(8.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.align(Alignment.CenterVertically)
|
||||
) {
|
||||
Text(
|
||||
text = "Enable Performance Mode",
|
||||
)
|
||||
Text(
|
||||
text = "Forces CPU and GPU to run at max clocks if available.",
|
||||
fontSize = 12.sp
|
||||
)
|
||||
Text(
|
||||
text = "OS power settings may override this.",
|
||||
fontSize = 12.sp
|
||||
)
|
||||
}
|
||||
Switch(checked = enablePerformanceMode.value, onCheckedChange = {
|
||||
enablePerformanceMode.value = !enablePerformanceMode.value
|
||||
})
|
||||
}
|
||||
val isImporting = remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
@ -1041,6 +1075,7 @@ class SettingViews {
|
||||
isGrid,
|
||||
useSwitchLayout,
|
||||
enableMotion,
|
||||
enablePerformanceMode,
|
||||
enableDebugLogs,
|
||||
enableStubLogs,
|
||||
enableInfoLogs,
|
||||
|
Loading…
x
Reference in New Issue
Block a user