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;
|
||||||
using Ryujinx.HLE.HOS.Applets;
|
using Ryujinx.HLE.HOS.Applets;
|
||||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||||
using Ryujinx.HLE.Ui;
|
using Ryujinx.HLE.UI;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -13,17 +13,17 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace LibRyujinx.Android
|
namespace LibRyujinx.Android
|
||||||
{
|
{
|
||||||
internal class AndroidUiHandler : IHostUiHandler, IDisposable
|
internal class AndroidUIHandler : IHostUIHandler, IDisposable
|
||||||
{
|
{
|
||||||
public IHostUiTheme HostUiTheme => throw new NotImplementedException();
|
|
||||||
|
|
||||||
public ManualResetEvent _waitEvent;
|
public ManualResetEvent _waitEvent;
|
||||||
public ManualResetEvent _responseEvent;
|
public ManualResetEvent _responseEvent;
|
||||||
private bool _isDisposed;
|
private bool _isDisposed;
|
||||||
private bool _isOkPressed;
|
private bool _isOkPressed;
|
||||||
private long _input;
|
private long _input;
|
||||||
|
|
||||||
public AndroidUiHandler()
|
public IHostUITheme HostUITheme => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public AndroidUIHandler()
|
||||||
{
|
{
|
||||||
_waitEvent = new ManualResetEvent(false);
|
_waitEvent = new ManualResetEvent(false);
|
||||||
_responseEvent = new ManualResetEvent(false);
|
_responseEvent = new ManualResetEvent(false);
|
||||||
@ -47,7 +47,7 @@ namespace LibRyujinx.Android
|
|||||||
return _isOkPressed;
|
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.setUiHandlerTitle(LibRyujinx.storeString("Software Keyboard"));
|
||||||
LibRyujinx.setUiHandlerMessage(LibRyujinx.storeString(args.HeaderText ?? ""));
|
LibRyujinx.setUiHandlerMessage(LibRyujinx.storeString(args.HeaderText ?? ""));
|
||||||
@ -81,7 +81,7 @@ namespace LibRyujinx.Android
|
|||||||
return _isOkPressed;
|
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}";
|
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.Primitives;
|
||||||
using LibRyujinx.Jni.References;
|
using LibRyujinx.Jni.References;
|
||||||
using LibRyujinx.Jni.Values;
|
using LibRyujinx.Jni.Values;
|
||||||
using LibRyujinx.Shared.Audio.Oboe;
|
|
||||||
using Rxmxnx.PInvoke;
|
using Rxmxnx.PInvoke;
|
||||||
using Ryujinx.Audio.Backends.OpenAL;
|
using Ryujinx.Audio.Backends.OpenAL;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
@ -233,8 +232,6 @@ namespace LibRyujinx
|
|||||||
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
|
||||||
var list = GetDlcContentList(GetStoredString(pathPtr), (ulong)(long)titleId);
|
var list = GetDlcContentList(GetStoredString(pathPtr), (ulong)(long)titleId);
|
||||||
|
|
||||||
debug_break(4);
|
|
||||||
|
|
||||||
return CreateStringArray(jEnv, list);
|
return CreateStringArray(jEnv, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#ifndef RYUJINXNATIVE_RYUIJNX_H
|
#ifndef RYUJINXNATIVE_RYUIJNX_H
|
||||||
#define RYUJINXNATIVE_RYUIJNX_H
|
#define RYUJINXNATIVE_RYUIJNX_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -36,25 +37,38 @@
|
|||||||
|
|
||||||
#define LoadLib(a) dlopen(a, RTLD_NOW)
|
#define LoadLib(a) dlopen(a, RTLD_NOW)
|
||||||
|
|
||||||
void* _ryujinxNative = NULL;
|
void *_ryujinxNative = NULL;
|
||||||
|
|
||||||
class UiHandler {
|
class UiHandler {
|
||||||
public:
|
public:
|
||||||
void setTitle(long storedTitle);
|
void setTitle(long storedTitle);
|
||||||
|
|
||||||
void setMessage(long storedMessage);
|
void setMessage(long storedMessage);
|
||||||
|
|
||||||
void setWatermark(long wm);
|
void setWatermark(long wm);
|
||||||
|
|
||||||
void setType(int t);
|
void setType(int t);
|
||||||
|
|
||||||
void setMode(int t);
|
void setMode(int t);
|
||||||
|
|
||||||
void setMinLength(int t);
|
void setMinLength(int t);
|
||||||
|
|
||||||
void setMaxLength(int t);
|
void setMaxLength(int t);
|
||||||
|
|
||||||
void setInitialText(long text);
|
void setInitialText(long text);
|
||||||
|
|
||||||
void setSubtitle(long text);
|
void setSubtitle(long text);
|
||||||
|
|
||||||
long getTitle();
|
long getTitle();
|
||||||
|
|
||||||
long getMessage();
|
long getMessage();
|
||||||
|
|
||||||
long getWatermark();
|
long getWatermark();
|
||||||
|
|
||||||
long getInitialText();
|
long getInitialText();
|
||||||
|
|
||||||
long getSubtitle();
|
long getSubtitle();
|
||||||
|
|
||||||
int type = 0;
|
int type = 0;
|
||||||
int keyboardMode = 0;
|
int keyboardMode = 0;
|
||||||
int min_length = -1;
|
int min_length = -1;
|
||||||
@ -69,11 +83,10 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Ryujinx imported functions
|
// Ryujinx imported functions
|
||||||
bool (*initialize)(char*) = NULL;
|
bool (*initialize)(char *) = NULL;
|
||||||
|
|
||||||
long _renderingThreadId = 0;
|
long _renderingThreadId = 0;
|
||||||
long _currentRenderingThreadId = 0;
|
JavaVM *_vm = nullptr;
|
||||||
JavaVM* _vm = nullptr;
|
|
||||||
jobject _mainActivity = nullptr;
|
jobject _mainActivity = nullptr;
|
||||||
jclass _mainActivityClass = nullptr;
|
jclass _mainActivityClass = nullptr;
|
||||||
string_helper str_helper = string_helper();
|
string_helper str_helper = string_helper();
|
||||||
|
@ -21,21 +21,20 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
|
|
||||||
jmethodID _updateFrameTime;
|
JNIEnv *_rendererEnv = nullptr;
|
||||||
JNIEnv* _rendererEnv = nullptr;
|
|
||||||
|
|
||||||
std::chrono::time_point<std::chrono::steady_clock, std::chrono::nanoseconds> _currentTimePoint;
|
std::chrono::time_point<std::chrono::steady_clock, std::chrono::nanoseconds> _currentTimePoint;
|
||||||
|
|
||||||
std::string progressInfo = "";
|
std::string progressInfo = "";
|
||||||
float progress = -1;
|
float progress = -1;
|
||||||
|
|
||||||
JNIEnv* getEnv(bool isRenderer){
|
JNIEnv *getEnv(bool isRenderer) {
|
||||||
JNIEnv* env;
|
JNIEnv *env;
|
||||||
if(isRenderer){
|
if (isRenderer) {
|
||||||
env = _rendererEnv;
|
env = _rendererEnv;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(env != nullptr)
|
if (env != nullptr)
|
||||||
return env;
|
return env;
|
||||||
|
|
||||||
auto result = _vm->AttachCurrentThread(&env, NULL);
|
auto result = _vm->AttachCurrentThread(&env, NULL);
|
||||||
@ -43,23 +42,23 @@ JNIEnv* getEnv(bool isRenderer){
|
|||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
void detachEnv(){
|
void detachEnv() {
|
||||||
auto result = _vm->DetachCurrentThread();
|
auto result = _vm->DetachCurrentThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jlong JNICALL
|
||||||
Java_org_ryujinx_android_NativeHelpers_getNativeWindow(
|
Java_org_ryujinx_android_NativeHelpers_getNativeWindow(
|
||||||
JNIEnv *env,
|
JNIEnv *env,
|
||||||
jobject instance,
|
jobject instance,
|
||||||
jobject surface) {
|
jobject surface) {
|
||||||
auto nativeWindow = ANativeWindow_fromSurface(env, surface);
|
auto nativeWindow = ANativeWindow_fromSurface(env, surface);
|
||||||
return nativeWindow == NULL ? -1 : (jlong) nativeWindow;
|
return nativeWindow == NULL ? -1 : (jlong) nativeWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_org_ryujinx_android_NativeHelpers_releaseNativeWindow(
|
Java_org_ryujinx_android_NativeHelpers_releaseNativeWindow(
|
||||||
JNIEnv *env,
|
JNIEnv *env,
|
||||||
jobject instance,
|
jobject instance,
|
||||||
jlong window) {
|
jlong window) {
|
||||||
@ -67,16 +66,16 @@ extern "C"
|
|||||||
|
|
||||||
if (nativeWindow != NULL)
|
if (nativeWindow != NULL)
|
||||||
ANativeWindow_release(nativeWindow);
|
ANativeWindow_release(nativeWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_org_ryujinx_android_NativeHelpers_attachCurrentThread(
|
Java_org_ryujinx_android_NativeHelpers_attachCurrentThread(
|
||||||
JNIEnv *env,
|
JNIEnv *env,
|
||||||
jobject instance) {
|
jobject instance) {
|
||||||
JavaVM* jvm = NULL;
|
JavaVM *jvm = NULL;
|
||||||
env->GetJavaVM(&jvm);
|
env->GetJavaVM(&jvm);
|
||||||
|
|
||||||
if(jvm != NULL)
|
if (jvm != NULL)
|
||||||
jvm->AttachCurrentThread(&env, NULL);
|
jvm->AttachCurrentThread(&env, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,41 +83,41 @@ JNIEXPORT void JNICALL
|
|||||||
Java_org_ryujinx_android_NativeHelpers_detachCurrentThread(
|
Java_org_ryujinx_android_NativeHelpers_detachCurrentThread(
|
||||||
JNIEnv *env,
|
JNIEnv *env,
|
||||||
jobject instance) {
|
jobject instance) {
|
||||||
JavaVM* jvm = NULL;
|
JavaVM *jvm = NULL;
|
||||||
env->GetJavaVM(&jvm);
|
env->GetJavaVM(&jvm);
|
||||||
|
|
||||||
if(jvm != NULL)
|
if (jvm != NULL)
|
||||||
jvm->DetachCurrentThread();
|
jvm->DetachCurrentThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
long createSurface(long native_surface, long instance)
|
long createSurface(long native_surface, long instance) {
|
||||||
{
|
|
||||||
auto nativeWindow = (ANativeWindow *) native_surface;
|
auto nativeWindow = (ANativeWindow *) native_surface;
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
auto vkInstance = (VkInstance)instance;
|
auto vkInstance = (VkInstance) instance;
|
||||||
auto fpCreateAndroidSurfaceKHR =
|
auto fpCreateAndroidSurfaceKHR =
|
||||||
reinterpret_cast<PFN_vkCreateAndroidSurfaceKHR>(vkGetInstanceProcAddr(vkInstance, "vkCreateAndroidSurfaceKHR"));
|
reinterpret_cast<PFN_vkCreateAndroidSurfaceKHR>(vkGetInstanceProcAddr(vkInstance,
|
||||||
|
"vkCreateAndroidSurfaceKHR"));
|
||||||
if (!fpCreateAndroidSurfaceKHR)
|
if (!fpCreateAndroidSurfaceKHR)
|
||||||
return -1;
|
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;
|
info.window = nativeWindow;
|
||||||
VK_CHECK(fpCreateAndroidSurfaceKHR(vkInstance, &info, nullptr, &surface));
|
VK_CHECK(fpCreateAndroidSurfaceKHR(vkInstance, &info, nullptr, &surface));
|
||||||
return (long)surface;
|
return (long) surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jlong JNICALL
|
||||||
Java_org_ryujinx_android_NativeHelpers_getCreateSurfacePtr(
|
Java_org_ryujinx_android_NativeHelpers_getCreateSurfacePtr(
|
||||||
JNIEnv *env,
|
JNIEnv *env,
|
||||||
jobject instance) {
|
jobject instance) {
|
||||||
return (jlong)createSurface;
|
return (jlong) createSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* getStringPointer(
|
char *getStringPointer(
|
||||||
JNIEnv *env,
|
JNIEnv *env,
|
||||||
jstring jS) {
|
jstring jS) {
|
||||||
const char *cparam = env->GetStringUTFChars(jS, 0);
|
const char *cparam = env->GetStringUTFChars(jS, 0);
|
||||||
auto len = env->GetStringUTFLength(jS);
|
auto len = env->GetStringUTFLength(jS);
|
||||||
char* s= new char[len];
|
char *s = new char[len];
|
||||||
strcpy(s, cparam);
|
strcpy(s, cparam);
|
||||||
env->ReleaseStringUTFChars(jS, cparam);
|
env->ReleaseStringUTFChars(jS, cparam);
|
||||||
|
|
||||||
@ -127,7 +126,7 @@ char* getStringPointer(
|
|||||||
|
|
||||||
jstring createString(
|
jstring createString(
|
||||||
JNIEnv *env,
|
JNIEnv *env,
|
||||||
char* ch) {
|
char *ch) {
|
||||||
auto str = env->NewStringUTF(ch);
|
auto str = env->NewStringUTF(ch);
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
@ -144,15 +143,9 @@ jstring createStringFromStdString(
|
|||||||
|
|
||||||
}
|
}
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT jlong JNICALL
|
void setRenderingThread() {
|
||||||
Java_org_ryujinx_android_MainActivity_getRenderingThreadId(JNIEnv *env, jobject thiz) {
|
|
||||||
return _currentRenderingThreadId;
|
|
||||||
}
|
|
||||||
extern "C"
|
|
||||||
void setRenderingThread(){
|
|
||||||
auto currentId = pthread_self();
|
auto currentId = pthread_self();
|
||||||
|
|
||||||
_currentRenderingThreadId = currentId;
|
|
||||||
_renderingThreadId = currentId;
|
_renderingThreadId = currentId;
|
||||||
|
|
||||||
_currentTimePoint = std::chrono::high_resolution_clock::now();
|
_currentTimePoint = std::chrono::high_resolution_clock::now();
|
||||||
@ -160,7 +153,7 @@ void setRenderingThread(){
|
|||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_org_ryujinx_android_MainActivity_initVm(JNIEnv *env, jobject thiz) {
|
Java_org_ryujinx_android_MainActivity_initVm(JNIEnv *env, jobject thiz) {
|
||||||
JavaVM* vm = nullptr;
|
JavaVM *vm = nullptr;
|
||||||
auto success = env->GetJavaVM(&vm);
|
auto success = env->GetJavaVM(&vm);
|
||||||
_vm = vm;
|
_vm = vm;
|
||||||
_mainActivity = thiz;
|
_mainActivity = thiz;
|
||||||
@ -171,25 +164,26 @@ extern "C"
|
|||||||
void onFrameEnd(double time) {
|
void onFrameEnd(double time) {
|
||||||
auto env = getEnv(true);
|
auto env = getEnv(true);
|
||||||
auto cl = env->FindClass("org/ryujinx/android/MainActivity");
|
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 now = std::chrono::high_resolution_clock::now();
|
||||||
auto nano = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
auto nano = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||||
now - _currentTimePoint).count();
|
now - _currentTimePoint).count();
|
||||||
env->CallStaticVoidMethod(cl, _updateFrameTime,
|
env->CallStaticVoidMethod(cl, frameEnd,
|
||||||
nano);
|
nano);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
void setProgressInfo(char* info, float progressValue) {
|
void setProgressInfo(char *info, float progressValue) {
|
||||||
progressInfo = std::string (info);
|
progressInfo = std::string(info);
|
||||||
progress = progressValue;
|
progress = progressValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isInitialOrientationFlipped = true;
|
bool isInitialOrientationFlipped = true;
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
void setCurrentTransform(long native_window, int transform){
|
void setCurrentTransform(long native_window, int transform) {
|
||||||
if(native_window == 0 || native_window == -1)
|
if (native_window == 0 || native_window == -1)
|
||||||
return;
|
return;
|
||||||
auto nativeWindow = (ANativeWindow *) native_window;
|
auto nativeWindow = (ANativeWindow *) native_window;
|
||||||
|
|
||||||
@ -206,7 +200,9 @@ void setCurrentTransform(long native_window, int transform){
|
|||||||
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_ROTATE_90;
|
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_ROTATE_90;
|
||||||
break;
|
break;
|
||||||
case 0x4:
|
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;
|
break;
|
||||||
case 0x8:
|
case 0x8:
|
||||||
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_ROTATE_270;
|
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_ROTATE_270;
|
||||||
@ -232,7 +228,8 @@ void setCurrentTransform(long native_window, int transform){
|
|||||||
break;
|
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"
|
extern "C"
|
||||||
@ -260,12 +257,12 @@ Java_org_ryujinx_android_NativeHelpers_loadDriver(JNIEnv *env, jobject thiz,
|
|||||||
delete privateAppsPath;
|
delete privateAppsPath;
|
||||||
delete driverName;
|
delete driverName;
|
||||||
|
|
||||||
return (jlong)handle;
|
return (jlong) handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
void debug_break(int code){
|
void debug_break(int code) {
|
||||||
if(code >= 3)
|
if (code >= 3)
|
||||||
int r = 0;
|
int r = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,14 +312,14 @@ Java_org_ryujinx_android_NativeHelpers_getProgressInfo(JNIEnv *env, jobject thiz
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
long storeString(char* str){
|
long storeString(char *str) {
|
||||||
return str_helper.store_cstring(str);
|
return str_helper.store_cstring(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
const char* getString(long id){
|
const char *getString(long id) {
|
||||||
auto str = str_helper.get_stored(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());
|
::strcpy(cstr, str.c_str());
|
||||||
return cstr;
|
return cstr;
|
||||||
}
|
}
|
||||||
@ -396,7 +393,7 @@ Java_org_ryujinx_android_NativeHelpers_getUiHandlerRequestMessage(JNIEnv *env, j
|
|||||||
|
|
||||||
|
|
||||||
void UiHandler::setTitle(long storedTitle) {
|
void UiHandler::setTitle(long storedTitle) {
|
||||||
if(title != -1){
|
if (title != -1) {
|
||||||
str_helper.get_stored(title);
|
str_helper.get_stored(title);
|
||||||
title = -1;
|
title = -1;
|
||||||
}
|
}
|
||||||
@ -405,7 +402,7 @@ void UiHandler::setTitle(long storedTitle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UiHandler::setMessage(long storedMessage) {
|
void UiHandler::setMessage(long storedMessage) {
|
||||||
if(message != -1){
|
if (message != -1) {
|
||||||
str_helper.get_stored(message);
|
str_helper.get_stored(message);
|
||||||
message = -1;
|
message = -1;
|
||||||
}
|
}
|
||||||
@ -430,7 +427,7 @@ long UiHandler::getMessage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UiHandler::setWatermark(long wm) {
|
void UiHandler::setWatermark(long wm) {
|
||||||
if(watermark != -1){
|
if (watermark != -1) {
|
||||||
str_helper.get_stored(watermark);
|
str_helper.get_stored(watermark);
|
||||||
watermark = -1;
|
watermark = -1;
|
||||||
}
|
}
|
||||||
@ -453,7 +450,7 @@ long UiHandler::getWatermark() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UiHandler::setInitialText(long text) {
|
void UiHandler::setInitialText(long text) {
|
||||||
if(initialText != -1){
|
if (initialText != -1) {
|
||||||
str_helper.get_stored(watermark);
|
str_helper.get_stored(watermark);
|
||||||
initialText = -1;
|
initialText = -1;
|
||||||
}
|
}
|
||||||
@ -462,7 +459,7 @@ void UiHandler::setInitialText(long text) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UiHandler::setSubtitle(long text) {
|
void UiHandler::setSubtitle(long text) {
|
||||||
if(subtitle != -1){
|
if (subtitle != -1) {
|
||||||
str_helper.get_stored(subtitle);
|
str_helper.get_stored(subtitle);
|
||||||
subtitle = -1;
|
subtitle = -1;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package org.ryujinx.android
|
|||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
|
||||||
import android.view.SurfaceHolder
|
import android.view.SurfaceHolder
|
||||||
import android.view.SurfaceView
|
import android.view.SurfaceView
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
@ -130,7 +129,8 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
|
|||||||
if (c >= 1000) {
|
if (c >= 1000) {
|
||||||
if (helper.getProgressValue() == -1f)
|
if (helper.getProgressValue() == -1f)
|
||||||
progress?.apply {
|
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
|
c = 0
|
||||||
mainViewModel.updateStats(
|
mainViewModel.updateStats(
|
||||||
@ -144,26 +144,6 @@ class GameHost(context: Context?, private val mainViewModel: MainViewModel) : Su
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun runGame() {
|
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 {
|
thread {
|
||||||
mainViewModel.activity.uiHandler.listen()
|
mainViewModel.activity.uiHandler.listen()
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
package org.ryujinx.android
|
package org.ryujinx.android
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Intent
|
|
||||||
import android.content.pm.ActivityInfo
|
import android.content.pm.ActivityInfo
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.view.KeyEvent
|
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.MainViewModel
|
||||||
import org.ryujinx.android.viewmodels.QuickSettings
|
import org.ryujinx.android.viewmodels.QuickSettings
|
||||||
import org.ryujinx.android.views.MainView
|
import org.ryujinx.android.views.MainView
|
||||||
import kotlin.math.abs
|
|
||||||
|
|
||||||
|
|
||||||
class MainActivity : BaseActivity() {
|
class MainActivity : BaseActivity() {
|
||||||
@ -31,24 +28,23 @@ class MainActivity : BaseActivity() {
|
|||||||
private lateinit var motionSensorManager: MotionSensorManager
|
private lateinit var motionSensorManager: MotionSensorManager
|
||||||
private var _isInit: Boolean = false
|
private var _isInit: Boolean = false
|
||||||
var isGameRunning = false
|
var isGameRunning = false
|
||||||
|
var isActive = false
|
||||||
var storageHelper: SimpleStorageHelper? = null
|
var storageHelper: SimpleStorageHelper? = null
|
||||||
lateinit var uiHandler: UiHandler
|
lateinit var uiHandler: UiHandler
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
var mainViewModel: MainViewModel? = null
|
var mainViewModel: MainViewModel? = null
|
||||||
var AppPath : String = ""
|
var AppPath: String = ""
|
||||||
var StorageHelper: SimpleStorageHelper? = null
|
var StorageHelper: SimpleStorageHelper? = null
|
||||||
val performanceMonitor = PerformanceMonitor()
|
val performanceMonitor = PerformanceMonitor()
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun updateRenderSessionPerformance(gameTime : Long)
|
fun frameEnded(gameTime: Long) {
|
||||||
{
|
mainViewModel?.activity?.apply {
|
||||||
if(gameTime <= 0)
|
if (isActive && QuickSettings(this).enablePerformanceMode) {
|
||||||
return
|
mainViewModel?.performanceManager?.setTurboMode(true);
|
||||||
|
}
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
||||||
mainViewModel?.performanceManager?.updateRenderingSessionTime(gameTime)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mainViewModel?.gameHost?.hideProgressIndicator()
|
mainViewModel?.gameHost?.hideProgressIndicator()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,7 +56,6 @@ class MainActivity : BaseActivity() {
|
|||||||
initVm()
|
initVm()
|
||||||
}
|
}
|
||||||
|
|
||||||
external fun getRenderingThreadId() : Long
|
|
||||||
private external fun initVm()
|
private external fun initVm()
|
||||||
|
|
||||||
private fun initialize() {
|
private fun initialize() {
|
||||||
@ -70,26 +65,52 @@ class MainActivity : BaseActivity() {
|
|||||||
val appPath: String = AppPath
|
val appPath: String = AppPath
|
||||||
|
|
||||||
var quickSettings = QuickSettings(this)
|
var quickSettings = QuickSettings(this)
|
||||||
RyujinxNative.instance.loggingSetEnabled(LogLevel.Debug.ordinal, quickSettings.enableDebugLogs)
|
RyujinxNative.instance.loggingSetEnabled(
|
||||||
RyujinxNative.instance.loggingSetEnabled(LogLevel.Info.ordinal, quickSettings.enableInfoLogs)
|
LogLevel.Debug.ordinal,
|
||||||
RyujinxNative.instance.loggingSetEnabled(LogLevel.Stub.ordinal, quickSettings.enableStubLogs)
|
quickSettings.enableDebugLogs
|
||||||
RyujinxNative.instance.loggingSetEnabled(LogLevel.Warning.ordinal, quickSettings.enableWarningLogs)
|
)
|
||||||
RyujinxNative.instance.loggingSetEnabled(LogLevel.Error.ordinal, quickSettings.enableErrorLogs)
|
RyujinxNative.instance.loggingSetEnabled(
|
||||||
RyujinxNative.instance.loggingSetEnabled(LogLevel.AccessLog.ordinal, quickSettings.enableAccessLogs)
|
LogLevel.Info.ordinal,
|
||||||
RyujinxNative.instance.loggingSetEnabled(LogLevel.Guest.ordinal, quickSettings.enableGuestLogs)
|
quickSettings.enableInfoLogs
|
||||||
RyujinxNative.instance.loggingSetEnabled(LogLevel.Trace.ordinal, quickSettings.enableTraceLogs)
|
)
|
||||||
val success = RyujinxNative.instance.initialize(NativeHelpers.instance.storeStringJava(appPath))
|
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()
|
uiHandler = UiHandler()
|
||||||
_isInit = success
|
_isInit = success
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
motionSensorManager = MotionSensorManager(this)
|
motionSensorManager = MotionSensorManager(this)
|
||||||
Thread.setDefaultUncaughtExceptionHandler(crashHandler)
|
Thread.setDefaultUncaughtExceptionHandler(crashHandler)
|
||||||
|
|
||||||
if(
|
if (
|
||||||
!Environment.isExternalStorageManager()
|
!Environment.isExternalStorageManager()
|
||||||
) {
|
) {
|
||||||
storageHelper?.storage?.requestFullStorageAccess()
|
storageHelper?.storage?.requestFullStorageAccess()
|
||||||
@ -99,8 +120,9 @@ class MainActivity : BaseActivity() {
|
|||||||
|
|
||||||
initialize()
|
initialize()
|
||||||
|
|
||||||
window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
window.attributes.layoutInDisplayCutoutMode =
|
||||||
WindowCompat.setDecorFitsSystemWindows(window,false)
|
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
||||||
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
|
|
||||||
mainViewModel = MainViewModel(this)
|
mainViewModel = MainViewModel(this)
|
||||||
mainViewModel!!.physicalControllerManager = physicalControllerManager
|
mainViewModel!!.physicalControllerManager = physicalControllerManager
|
||||||
@ -133,25 +155,6 @@ class MainActivity : BaseActivity() {
|
|||||||
storageHelper?.onRestoreInstanceState(savedInstanceState)
|
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) {
|
fun setFullScreen(fullscreen: Boolean) {
|
||||||
requestedOrientation =
|
requestedOrientation =
|
||||||
if (fullscreen) ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE else ActivityInfo.SCREEN_ORIENTATION_FULL_USER
|
if (fullscreen) ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE else ActivityInfo.SCREEN_ORIENTATION_FULL_USER
|
||||||
@ -190,20 +193,19 @@ class MainActivity : BaseActivity() {
|
|||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
super.onStop()
|
super.onStop()
|
||||||
|
isActive = false
|
||||||
|
|
||||||
if(isGameRunning) {
|
if (isGameRunning) {
|
||||||
NativeHelpers.instance.setTurboMode(false)
|
mainViewModel?.performanceManager?.setTurboMode(false)
|
||||||
force60HzRefreshRate(false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
isActive = true
|
||||||
|
|
||||||
if(isGameRunning) {
|
if (isGameRunning) {
|
||||||
setFullScreen(true)
|
setFullScreen(true)
|
||||||
NativeHelpers.instance.setTurboMode(true)
|
|
||||||
force60HzRefreshRate(true)
|
|
||||||
if (QuickSettings(this).enableMotion)
|
if (QuickSettings(this).enableMotion)
|
||||||
motionSensorManager.register()
|
motionSensorManager.register()
|
||||||
}
|
}
|
||||||
@ -211,10 +213,10 @@ class MainActivity : BaseActivity() {
|
|||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
|
isActive = true
|
||||||
|
|
||||||
if(isGameRunning) {
|
if (isGameRunning) {
|
||||||
NativeHelpers.instance.setTurboMode(false)
|
mainViewModel?.performanceManager?.setTurboMode(false)
|
||||||
force60HzRefreshRate(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
motionSensorManager.unregister()
|
motionSensorManager.unregister()
|
||||||
|
@ -1,49 +1,31 @@
|
|||||||
package org.ryujinx.android
|
package org.ryujinx.android
|
||||||
|
|
||||||
import android.os.Build
|
import android.content.Intent
|
||||||
import android.os.PerformanceHintManager
|
import kotlin.math.abs
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
|
|
||||||
class PerformanceManager(private val performanceHintManager: PerformanceHintManager) {
|
class PerformanceManager(private val activity: MainActivity) {
|
||||||
private var _isEnabled: Boolean = false
|
companion object {
|
||||||
private var renderingSession: PerformanceHintManager.Session? = null
|
fun force60HzRefreshRate(enable: Boolean, activity: MainActivity) {
|
||||||
private val DEFAULT_TARGET_NS = 16666666L
|
// Hack for MIUI devices since they don't support the standard Android APIs
|
||||||
|
try {
|
||||||
@RequiresApi(Build.VERSION_CODES.S)
|
val setFpsIntent = Intent("com.miui.powerkeeper.SET_ACTIVITY_FPS")
|
||||||
fun initializeRenderingSession(threadId : Long){
|
setFpsIntent.putExtra("package_name", "org.ryujinx.android")
|
||||||
if(!_isEnabled || renderingSession != null)
|
setFpsIntent.putExtra("isEnter", enable)
|
||||||
return
|
activity.sendBroadcast(setFpsIntent)
|
||||||
|
} catch (_: Exception) {
|
||||||
val threads = IntArray(1)
|
|
||||||
threads[0] = threadId.toInt()
|
|
||||||
renderingSession = performanceHintManager.createHintSession(threads, DEFAULT_TARGET_NS)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.S)
|
if (enable)
|
||||||
fun closeCurrentRenderingSession() {
|
activity.display?.supportedModes?.minByOrNull { abs(it.refreshRate - 60f) }
|
||||||
if (_isEnabled)
|
?.let { activity.window.attributes.preferredDisplayModeId = it.modeId }
|
||||||
renderingSession?.apply {
|
else
|
||||||
renderingSession = null
|
activity.display?.supportedModes?.maxByOrNull { it.refreshRate }
|
||||||
this.close()
|
?.let { activity.window.attributes.preferredDisplayModeId = it.modeId }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun enable(){
|
fun setTurboMode(enable: Boolean) {
|
||||||
_isEnabled = true
|
NativeHelpers.instance.setTurboMode(enable)
|
||||||
}
|
force60HzRefreshRate(enable, activity)
|
||||||
|
|
||||||
@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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package org.ryujinx.android.viewmodels
|
package org.ryujinx.android.viewmodels
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.PerformanceHintManager
|
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import com.anggrayudi.storage.extension.launchOnUiThread
|
import com.anggrayudi.storage.extension.launchOnUiThread
|
||||||
@ -49,16 +46,12 @@ class MainViewModel(val activity: MainActivity) {
|
|||||||
field = value
|
field = value
|
||||||
field?.setProgressStates(showLoading, progressValue, progress)
|
field?.setProgressStates(showLoading, progressValue, progress)
|
||||||
}
|
}
|
||||||
var navController : NavHostController? = null
|
var navController: NavHostController? = null
|
||||||
|
|
||||||
var homeViewModel: HomeViewModel = HomeViewModel(activity, this)
|
var homeViewModel: HomeViewModel = HomeViewModel(activity, this)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
performanceManager = PerformanceManager(activity)
|
||||||
val hintService =
|
|
||||||
activity.getSystemService(Context.PERFORMANCE_HINT_SERVICE) as PerformanceHintManager
|
|
||||||
performanceManager = PerformanceManager(hintService)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun closeGame() {
|
fun closeGame() {
|
||||||
@ -70,14 +63,14 @@ class MainViewModel(val activity: MainActivity) {
|
|||||||
motionSensorManager?.setControllerId(-1)
|
motionSensorManager?.setControllerId(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refreshFirmwareVersion(){
|
fun refreshFirmwareVersion() {
|
||||||
var handle = RyujinxNative.instance.deviceGetInstalledFirmwareVersion()
|
var handle = RyujinxNative.instance.deviceGetInstalledFirmwareVersion()
|
||||||
if(handle != -1L) {
|
if (handle != -1L) {
|
||||||
firmwareVersion = NativeHelpers.instance.getStringJava(handle)
|
firmwareVersion = NativeHelpers.instance.getStringJava(handle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadGame(game:GameModel) : Boolean {
|
fun loadGame(game: GameModel): Boolean {
|
||||||
val nativeRyujinx = RyujinxNative.instance
|
val nativeRyujinx = RyujinxNative.instance
|
||||||
|
|
||||||
val descriptor = game.open()
|
val descriptor = game.open()
|
||||||
@ -188,7 +181,7 @@ class MainViewModel(val activity: MainActivity) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadMiiEditor() : Boolean {
|
fun loadMiiEditor(): Boolean {
|
||||||
val nativeRyujinx = RyujinxNative.instance
|
val nativeRyujinx = RyujinxNative.instance
|
||||||
|
|
||||||
gameModel = null
|
gameModel = null
|
||||||
@ -292,42 +285,42 @@ class MainViewModel(val activity: MainActivity) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clearPptcCache(titleId :String){
|
fun clearPptcCache(titleId: String) {
|
||||||
if(titleId.isNotEmpty()){
|
if (titleId.isNotEmpty()) {
|
||||||
val basePath = MainActivity.AppPath + "/games/$titleId/cache/cpu"
|
val basePath = MainActivity.AppPath + "/games/$titleId/cache/cpu"
|
||||||
if(File(basePath).exists()){
|
if (File(basePath).exists()) {
|
||||||
var caches = mutableListOf<String>()
|
var caches = mutableListOf<String>()
|
||||||
|
|
||||||
val mainCache = basePath + "${File.separator}0"
|
val mainCache = basePath + "${File.separator}0"
|
||||||
File(mainCache).listFiles()?.forEach {
|
File(mainCache).listFiles()?.forEach {
|
||||||
if(it.isFile && it.name.endsWith(".cache"))
|
if (it.isFile && it.name.endsWith(".cache"))
|
||||||
caches.add(it.absolutePath)
|
caches.add(it.absolutePath)
|
||||||
}
|
}
|
||||||
val backupCache = basePath + "${File.separator}1"
|
val backupCache = basePath + "${File.separator}1"
|
||||||
File(backupCache).listFiles()?.forEach {
|
File(backupCache).listFiles()?.forEach {
|
||||||
if(it.isFile && it.name.endsWith(".cache"))
|
if (it.isFile && it.name.endsWith(".cache"))
|
||||||
caches.add(it.absolutePath)
|
caches.add(it.absolutePath)
|
||||||
}
|
}
|
||||||
for(path in caches)
|
for (path in caches)
|
||||||
File(path).delete()
|
File(path).delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun purgeShaderCache(titleId :String) {
|
fun purgeShaderCache(titleId: String) {
|
||||||
if(titleId.isNotEmpty()){
|
if (titleId.isNotEmpty()) {
|
||||||
val basePath = MainActivity.AppPath + "/games/$titleId/cache/shader"
|
val basePath = MainActivity.AppPath + "/games/$titleId/cache/shader"
|
||||||
if(File(basePath).exists()){
|
if (File(basePath).exists()) {
|
||||||
var caches = mutableListOf<String>()
|
var caches = mutableListOf<String>()
|
||||||
File(basePath).listFiles()?.forEach {
|
File(basePath).listFiles()?.forEach {
|
||||||
if(!it.isFile)
|
if (!it.isFile)
|
||||||
it.delete()
|
it.delete()
|
||||||
else{
|
else {
|
||||||
if(it.name.endsWith(".toc") || it.name.endsWith(".data"))
|
if (it.name.endsWith(".toc") || it.name.endsWith(".data"))
|
||||||
caches.add(it.absolutePath)
|
caches.add(it.absolutePath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(path in caches)
|
for (path in caches)
|
||||||
File(path).delete()
|
File(path).delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -347,7 +340,7 @@ class MainViewModel(val activity: MainActivity) {
|
|||||||
fifo: Double,
|
fifo: Double,
|
||||||
gameFps: Double,
|
gameFps: Double,
|
||||||
gameTime: Double
|
gameTime: Double
|
||||||
){
|
) {
|
||||||
fifoState?.apply {
|
fifoState?.apply {
|
||||||
this.value = fifo
|
this.value = fifo
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,11 @@ class QuickSettings(val activity: Activity) {
|
|||||||
var isHostMapped: Boolean
|
var isHostMapped: Boolean
|
||||||
var enableShaderCache: Boolean
|
var enableShaderCache: Boolean
|
||||||
var enableTextureRecompression: Boolean
|
var enableTextureRecompression: Boolean
|
||||||
var resScale : Float
|
var resScale: Float
|
||||||
var isGrid : Boolean
|
var isGrid: Boolean
|
||||||
var useSwitchLayout : Boolean
|
var useSwitchLayout: Boolean
|
||||||
var enableMotion : Boolean
|
var enableMotion: Boolean
|
||||||
|
var enablePerformanceMode: Boolean
|
||||||
|
|
||||||
// Logs
|
// Logs
|
||||||
var enableDebugLogs: Boolean
|
var enableDebugLogs: Boolean
|
||||||
@ -29,7 +30,8 @@ class QuickSettings(val activity: Activity) {
|
|||||||
var enableAccessLogs: Boolean
|
var enableAccessLogs: Boolean
|
||||||
var enableTraceLogs: Boolean
|
var enableTraceLogs: Boolean
|
||||||
|
|
||||||
private var sharedPref: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity)
|
private var sharedPref: SharedPreferences =
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
isHostMapped = sharedPref.getBoolean("isHostMapped", true)
|
isHostMapped = sharedPref.getBoolean("isHostMapped", true)
|
||||||
@ -45,6 +47,7 @@ class QuickSettings(val activity: Activity) {
|
|||||||
isGrid = sharedPref.getBoolean("isGrid", true)
|
isGrid = sharedPref.getBoolean("isGrid", true)
|
||||||
useSwitchLayout = sharedPref.getBoolean("useSwitchLayout", true)
|
useSwitchLayout = sharedPref.getBoolean("useSwitchLayout", true)
|
||||||
enableMotion = sharedPref.getBoolean("enableMotion", true)
|
enableMotion = sharedPref.getBoolean("enableMotion", true)
|
||||||
|
enablePerformanceMode = sharedPref.getBoolean("enablePerformanceMode", true)
|
||||||
|
|
||||||
enableDebugLogs = sharedPref.getBoolean("enableDebugLogs", false)
|
enableDebugLogs = sharedPref.getBoolean("enableDebugLogs", false)
|
||||||
enableStubLogs = sharedPref.getBoolean("enableStubLogs", false)
|
enableStubLogs = sharedPref.getBoolean("enableStubLogs", false)
|
||||||
@ -56,7 +59,7 @@ class QuickSettings(val activity: Activity) {
|
|||||||
enableTraceLogs = sharedPref.getBoolean("enableStubLogs", false)
|
enableTraceLogs = sharedPref.getBoolean("enableStubLogs", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun save(){
|
fun save() {
|
||||||
val editor = sharedPref.edit()
|
val editor = sharedPref.edit()
|
||||||
|
|
||||||
editor.putBoolean("isHostMapped", isHostMapped)
|
editor.putBoolean("isHostMapped", isHostMapped)
|
||||||
@ -72,6 +75,7 @@ class QuickSettings(val activity: Activity) {
|
|||||||
editor.putBoolean("isGrid", isGrid)
|
editor.putBoolean("isGrid", isGrid)
|
||||||
editor.putBoolean("useSwitchLayout", useSwitchLayout)
|
editor.putBoolean("useSwitchLayout", useSwitchLayout)
|
||||||
editor.putBoolean("enableMotion", enableMotion)
|
editor.putBoolean("enableMotion", enableMotion)
|
||||||
|
editor.putBoolean("enablePerformanceMode", enablePerformanceMode)
|
||||||
|
|
||||||
editor.putBoolean("enableDebugLogs", enableDebugLogs)
|
editor.putBoolean("enableDebugLogs", enableDebugLogs)
|
||||||
editor.putBoolean("enableStubLogs", enableStubLogs)
|
editor.putBoolean("enableStubLogs", enableStubLogs)
|
||||||
|
@ -56,6 +56,7 @@ class SettingsViewModel(var navController: NavHostController, val activity: Main
|
|||||||
isGrid: MutableState<Boolean>,
|
isGrid: MutableState<Boolean>,
|
||||||
useSwitchLayout: MutableState<Boolean>,
|
useSwitchLayout: MutableState<Boolean>,
|
||||||
enableMotion: MutableState<Boolean>,
|
enableMotion: MutableState<Boolean>,
|
||||||
|
enablePerformanceMode: MutableState<Boolean>,
|
||||||
enableDebugLogs: MutableState<Boolean>,
|
enableDebugLogs: MutableState<Boolean>,
|
||||||
enableStubLogs: MutableState<Boolean>,
|
enableStubLogs: MutableState<Boolean>,
|
||||||
enableInfoLogs: MutableState<Boolean>,
|
enableInfoLogs: MutableState<Boolean>,
|
||||||
@ -80,6 +81,7 @@ class SettingsViewModel(var navController: NavHostController, val activity: Main
|
|||||||
isGrid.value = sharedPref.getBoolean("isGrid", true)
|
isGrid.value = sharedPref.getBoolean("isGrid", true)
|
||||||
useSwitchLayout.value = sharedPref.getBoolean("useSwitchLayout", true)
|
useSwitchLayout.value = sharedPref.getBoolean("useSwitchLayout", true)
|
||||||
enableMotion.value = sharedPref.getBoolean("enableMotion", true)
|
enableMotion.value = sharedPref.getBoolean("enableMotion", true)
|
||||||
|
enablePerformanceMode.value = sharedPref.getBoolean("enablePerformanceMode", false)
|
||||||
|
|
||||||
enableDebugLogs.value = sharedPref.getBoolean("enableDebugLogs", false)
|
enableDebugLogs.value = sharedPref.getBoolean("enableDebugLogs", false)
|
||||||
enableStubLogs.value = sharedPref.getBoolean("enableStubLogs", false)
|
enableStubLogs.value = sharedPref.getBoolean("enableStubLogs", false)
|
||||||
@ -105,6 +107,7 @@ class SettingsViewModel(var navController: NavHostController, val activity: Main
|
|||||||
isGrid: MutableState<Boolean>,
|
isGrid: MutableState<Boolean>,
|
||||||
useSwitchLayout: MutableState<Boolean>,
|
useSwitchLayout: MutableState<Boolean>,
|
||||||
enableMotion: MutableState<Boolean>,
|
enableMotion: MutableState<Boolean>,
|
||||||
|
enablePerformanceMode: MutableState<Boolean>,
|
||||||
enableDebugLogs: MutableState<Boolean>,
|
enableDebugLogs: MutableState<Boolean>,
|
||||||
enableStubLogs: MutableState<Boolean>,
|
enableStubLogs: MutableState<Boolean>,
|
||||||
enableInfoLogs: MutableState<Boolean>,
|
enableInfoLogs: MutableState<Boolean>,
|
||||||
@ -129,6 +132,7 @@ class SettingsViewModel(var navController: NavHostController, val activity: Main
|
|||||||
editor.putBoolean("isGrid", isGrid.value)
|
editor.putBoolean("isGrid", isGrid.value)
|
||||||
editor.putBoolean("useSwitchLayout", useSwitchLayout.value)
|
editor.putBoolean("useSwitchLayout", useSwitchLayout.value)
|
||||||
editor.putBoolean("enableMotion", enableMotion.value)
|
editor.putBoolean("enableMotion", enableMotion.value)
|
||||||
|
editor.putBoolean("enablePerformanceMode", enablePerformanceMode.value)
|
||||||
|
|
||||||
editor.putBoolean("enableDebugLogs", enableDebugLogs.value)
|
editor.putBoolean("enableDebugLogs", enableDebugLogs.value)
|
||||||
editor.putBoolean("enableStubLogs", enableStubLogs.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
|
selectedFirmwareFile = null
|
||||||
selectedFirmwareVersion = ""
|
selectedFirmwareVersion = ""
|
||||||
installState.value = FirmwareInstallState.None
|
installState.value = FirmwareInstallState.None
|
||||||
@ -263,7 +267,7 @@ class SettingsViewModel(var navController: NavHostController, val activity: Main
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
enum class FirmwareInstallState{
|
enum class FirmwareInstallState {
|
||||||
None,
|
None,
|
||||||
Cancelled,
|
Cancelled,
|
||||||
Verifying,
|
Verifying,
|
||||||
|
@ -57,6 +57,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.rotate
|
import androidx.compose.ui.draw.rotate
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import com.anggrayudi.storage.file.extension
|
import com.anggrayudi.storage.file.extension
|
||||||
import org.ryujinx.android.Helpers
|
import org.ryujinx.android.Helpers
|
||||||
@ -122,6 +123,7 @@ class SettingViews {
|
|||||||
val isGrid = remember { mutableStateOf(true) }
|
val isGrid = remember { mutableStateOf(true) }
|
||||||
val useSwitchLayout = remember { mutableStateOf(true) }
|
val useSwitchLayout = remember { mutableStateOf(true) }
|
||||||
val enableMotion = remember { mutableStateOf(true) }
|
val enableMotion = remember { mutableStateOf(true) }
|
||||||
|
val enablePerformanceMode = remember { mutableStateOf(true) }
|
||||||
|
|
||||||
val enableDebugLogs = remember { mutableStateOf(true) }
|
val enableDebugLogs = remember { mutableStateOf(true) }
|
||||||
val enableStubLogs = remember { mutableStateOf(true) }
|
val enableStubLogs = remember { mutableStateOf(true) }
|
||||||
@ -144,6 +146,7 @@ class SettingViews {
|
|||||||
isGrid,
|
isGrid,
|
||||||
useSwitchLayout,
|
useSwitchLayout,
|
||||||
enableMotion,
|
enableMotion,
|
||||||
|
enablePerformanceMode,
|
||||||
enableDebugLogs,
|
enableDebugLogs,
|
||||||
enableStubLogs,
|
enableStubLogs,
|
||||||
enableInfoLogs,
|
enableInfoLogs,
|
||||||
@ -177,6 +180,7 @@ class SettingViews {
|
|||||||
isGrid,
|
isGrid,
|
||||||
useSwitchLayout,
|
useSwitchLayout,
|
||||||
enableMotion,
|
enableMotion,
|
||||||
|
enablePerformanceMode,
|
||||||
enableDebugLogs,
|
enableDebugLogs,
|
||||||
enableStubLogs,
|
enableStubLogs,
|
||||||
enableInfoLogs,
|
enableInfoLogs,
|
||||||
@ -192,9 +196,11 @@ class SettingViews {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}) { contentPadding ->
|
}) { contentPadding ->
|
||||||
Column(modifier = Modifier
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
.padding(contentPadding)
|
.padding(contentPadding)
|
||||||
.verticalScroll(rememberScrollState())) {
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
ExpandableView(onCardArrowClick = { }, title = "App") {
|
ExpandableView(onCardArrowClick = { }, title = "App") {
|
||||||
Column(modifier = Modifier.fillMaxWidth()) {
|
Column(modifier = Modifier.fillMaxWidth()) {
|
||||||
Row(
|
Row(
|
||||||
@ -303,9 +309,9 @@ class SettingViews {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(showFirwmareDialog.value) {
|
if (showFirwmareDialog.value) {
|
||||||
AlertDialog(onDismissRequest = {
|
AlertDialog(onDismissRequest = {
|
||||||
if(firmwareInstallState.value != FirmwareInstallState.Install) {
|
if (firmwareInstallState.value != FirmwareInstallState.Install) {
|
||||||
showFirwmareDialog.value = false
|
showFirwmareDialog.value = false
|
||||||
settingsViewModel.clearFirmwareSelection(firmwareInstallState)
|
settingsViewModel.clearFirmwareSelection(firmwareInstallState)
|
||||||
}
|
}
|
||||||
@ -327,7 +333,8 @@ class SettingViews {
|
|||||||
Text(text = "Select a zip or XCI file to install from.")
|
Text(text = "Select a zip or XCI file to install from.")
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.End,
|
horizontalArrangement = Arrangement.End,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
.padding(top = 4.dp)
|
.padding(top = 4.dp)
|
||||||
) {
|
) {
|
||||||
Button(onClick = {
|
Button(onClick = {
|
||||||
@ -350,7 +357,8 @@ class SettingViews {
|
|||||||
Text(text = "Firmware ${settingsViewModel.selectedFirmwareVersion} will be installed. Do you want to continue?")
|
Text(text = "Firmware ${settingsViewModel.selectedFirmwareVersion} will be installed. Do you want to continue?")
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.End,
|
horizontalArrangement = Arrangement.End,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
.padding(top = 4.dp)
|
.padding(top = 4.dp)
|
||||||
) {
|
) {
|
||||||
Button(onClick = {
|
Button(onClick = {
|
||||||
@ -358,9 +366,11 @@ class SettingViews {
|
|||||||
firmwareInstallState
|
firmwareInstallState
|
||||||
)
|
)
|
||||||
|
|
||||||
if(firmwareInstallState.value == FirmwareInstallState.None){
|
if (firmwareInstallState.value == FirmwareInstallState.None) {
|
||||||
showFirwmareDialog.value = false
|
showFirwmareDialog.value = false
|
||||||
settingsViewModel.clearFirmwareSelection(firmwareInstallState)
|
settingsViewModel.clearFirmwareSelection(
|
||||||
|
firmwareInstallState
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}, modifier = Modifier.padding(horizontal = 8.dp)) {
|
}, modifier = Modifier.padding(horizontal = 8.dp)) {
|
||||||
Text(text = "Yes")
|
Text(text = "Yes")
|
||||||
@ -376,34 +386,32 @@ class SettingViews {
|
|||||||
}
|
}
|
||||||
} else if (firmwareInstallState.value == FirmwareInstallState.Install) {
|
} else if (firmwareInstallState.value == FirmwareInstallState.Install) {
|
||||||
Text(text = "Installing Firmware ${settingsViewModel.selectedFirmwareVersion}...")
|
Text(text = "Installing Firmware ${settingsViewModel.selectedFirmwareVersion}...")
|
||||||
LinearProgressIndicator(modifier = Modifier
|
LinearProgressIndicator(
|
||||||
.padding(top = 4.dp))
|
modifier = Modifier
|
||||||
|
.padding(top = 4.dp)
|
||||||
|
)
|
||||||
} else if (firmwareInstallState.value == FirmwareInstallState.Verifying) {
|
} else if (firmwareInstallState.value == FirmwareInstallState.Verifying) {
|
||||||
Text(text = "Verifying selected file...")
|
Text(text = "Verifying selected file...")
|
||||||
LinearProgressIndicator(modifier = Modifier
|
LinearProgressIndicator(
|
||||||
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
)
|
)
|
||||||
}
|
} else if (firmwareInstallState.value == FirmwareInstallState.Done) {
|
||||||
else if (firmwareInstallState.value == FirmwareInstallState.Done) {
|
|
||||||
Text(text = "Installed Firmware ${settingsViewModel.selectedFirmwareVersion}")
|
Text(text = "Installed Firmware ${settingsViewModel.selectedFirmwareVersion}")
|
||||||
firmwareVersion.value = mainViewModel.firmwareVersion
|
firmwareVersion.value = mainViewModel.firmwareVersion
|
||||||
}
|
} else if (firmwareInstallState.value == FirmwareInstallState.Cancelled) {
|
||||||
else if(firmwareInstallState.value == FirmwareInstallState.Cancelled){
|
|
||||||
val file = settingsViewModel.selectedFirmwareFile
|
val file = settingsViewModel.selectedFirmwareFile
|
||||||
if(file != null){
|
if (file != null) {
|
||||||
if(file.extension == "xci" || file.extension == "zip"){
|
if (file.extension == "xci" || file.extension == "zip") {
|
||||||
if(settingsViewModel.selectedFirmwareVersion.isEmpty()) {
|
if (settingsViewModel.selectedFirmwareVersion.isEmpty()) {
|
||||||
Text(text = "Unable to find version in selected file")
|
Text(text = "Unable to find version in selected file")
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Text(text = "Unknown Error has occurred. Please check logs")
|
Text(text = "Unknown Error has occurred. Please check logs")
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Text(text = "File type is not supported")
|
Text(text = "File type is not supported")
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Text(text = "File type is not supported")
|
Text(text = "File type is not supported")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -503,6 +511,32 @@ class SettingViews {
|
|||||||
ignoreMissingServices.value = !ignoreMissingServices.value
|
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 {
|
val isImporting = remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
@ -1041,6 +1075,7 @@ class SettingViews {
|
|||||||
isGrid,
|
isGrid,
|
||||||
useSwitchLayout,
|
useSwitchLayout,
|
||||||
enableMotion,
|
enableMotion,
|
||||||
|
enablePerformanceMode,
|
||||||
enableDebugLogs,
|
enableDebugLogs,
|
||||||
enableStubLogs,
|
enableStubLogs,
|
||||||
enableInfoLogs,
|
enableInfoLogs,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user