summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/android/app/src/main/jni/native.cpp231
1 files changed, 164 insertions, 67 deletions
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 5d93da237..6a499b97d 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -17,6 +17,7 @@
#include "core/cpu_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/vfs_real.h"
+#include "core/hid/hid_core.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/perf_stats.h"
#include "jni/config.h"
@@ -26,10 +27,139 @@
namespace {
-ANativeWindow* s_surf{};
-std::unique_ptr<EmuWindow_Android> emu_window;
-std::atomic<bool> stop_run{true};
-Core::System system_;
+class EmulationSession final {
+public:
+ EmulationSession() = default;
+ ~EmulationSession() = default;
+
+ static EmulationSession& GetInstance() {
+ return s_instance;
+ }
+
+ const Core::System& System() const {
+ return system;
+ }
+
+ Core::System& System() {
+ return system;
+ }
+
+ const EmuWindow_Android& Window() const {
+ return *window;
+ }
+
+ EmuWindow_Android& Window() {
+ return *window;
+ }
+
+ ANativeWindow* NativeWindow() const {
+ return native_window;
+ }
+
+ void SetNativeWindow(ANativeWindow* native_window_) {
+ native_window = native_window_;
+ }
+
+ bool IsRunning() const {
+ return system.IsPoweredOn();
+ }
+
+ const Core::PerfStatsResults& PerfStats() const {
+ std::scoped_lock perf_stats_lock(perf_stats_mutex);
+ return perf_stats;
+ }
+
+ void SurfaceChanged() {
+ if (!IsRunning()) {
+ return;
+ }
+ window->OnSurfaceChanged(native_window);
+ }
+
+ Core::SystemResultStatus InitializeEmulation(const std::string& filepath) {
+ std::scoped_lock lock(mutex);
+
+ // Loads the configuration.
+ Config{};
+
+ // Create the render window.
+ window = std::make_unique<EmuWindow_Android>(&input_subsystem, native_window);
+
+ // Initialize system.
+ system.SetShuttingDown(false);
+ system.Initialize();
+ system.ApplySettings();
+ system.HIDCore().ReloadInputDevices();
+ system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
+ system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
+ system.GetFileSystemController().CreateFactories(*system.GetFilesystem());
+
+ // Load the ROM.
+ const Core::SystemResultStatus load_result{system.Load(EmulationSession::GetInstance().Window(), filepath)};
+ if (load_result != Core::SystemResultStatus::Success) {
+ return load_result;
+ }
+
+ // Complete initialization.
+ system.GPU().Start();
+ system.GetCpuManager().OnGpuReady();
+ system.RegisterExitCallback([&] { HaltEmulation(); });
+
+ return Core::SystemResultStatus::Success;
+ }
+
+ void ShutdownEmulation() {
+ std::scoped_lock lock(mutex);
+
+ // Unload user input.
+ system.HIDCore().UnloadInputDevices();
+
+ // Shutdown the main emulated process
+ system.DetachDebugger();
+ system.ShutdownMainProcess();
+ detached_tasks.WaitForAllTasks();
+
+ // Tear down the render window.
+ window.reset();
+ }
+
+ void HaltEmulation() {
+ cv.notify_one();
+ }
+
+ void RunEmulation() {
+ std::unique_lock lock(mutex);
+
+ void(system.Run());
+
+ if (system.DebuggerEnabled()) {
+ system.InitializeDebugger();
+ }
+
+ while (cv.wait_for(lock, std::chrono::seconds (1)) == std::cv_status::timeout) {
+ std::scoped_lock perf_stats_lock(perf_stats_mutex);
+ perf_stats = system.GetAndResetPerfStats();
+ }
+ }
+
+private:
+ static EmulationSession s_instance;
+
+ ANativeWindow* native_window{};
+
+ InputCommon::InputSubsystem input_subsystem;
+ Common::DetachedTasks detached_tasks;
+ Core::System system;
+
+ Core::PerfStatsResults perf_stats{};
+ mutable std::mutex perf_stats_mutex;
+
+ std::unique_ptr<EmuWindow_Android> window;
+ std::mutex mutex;
+ std::condition_variable_any cv;
+};
+
+/*static*/ EmulationSession EmulationSession::s_instance;
std::string UTF16ToUTF8(std::u16string_view input) {
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
@@ -56,7 +186,6 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
Common::Log::Initialize();
Common::Log::SetColorConsoleBackendEnabled(true);
Common::Log::Start();
- Common::DetachedTasks detached_tasks;
MicroProfileOnThreadCreate("EmuThread");
SCOPE_EXIT({ MicroProfileShutdown(); });
@@ -68,46 +197,13 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
return Core::SystemResultStatus::ErrorLoader;
}
- // Loads the configuration.
- Config{};
-
- system_.Initialize();
- system_.ApplySettings();
-
- InputCommon::InputSubsystem input_subsystem{};
-
- emu_window = std::make_unique<EmuWindow_Android>(&input_subsystem, s_surf);
-
- system_.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
- system_.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
- system_.GetFileSystemController().CreateFactories(*system_.GetFilesystem());
-
- const Core::SystemResultStatus load_result{system_.Load(*emu_window, filepath)};
-
- if (load_result != Core::SystemResultStatus::Success) {
- return load_result;
- }
-
- system_.GPU().Start();
- system_.GetCpuManager().OnGpuReady();
- system_.RegisterExitCallback([&] { exit(0); });
-
- void(system_.Run());
-
- if (system_.DebuggerEnabled()) {
- system_.InitializeDebugger();
- }
-
- stop_run = false;
- while (!stop_run) {
- std::this_thread::sleep_for(std::chrono::seconds(1));
+ const auto result = EmulationSession::GetInstance().InitializeEmulation(filepath);
+ if (result != Core::SystemResultStatus::Success) {
+ return result;
}
- system_.DetachDebugger();
- void(system_.Pause());
- system_.ShutdownMainProcess();
-
- detached_tasks.WaitForAllTasks();
+ EmulationSession::GetInstance().RunEmulation();
+ EmulationSession::GetInstance().ShutdownEmulation();
return Core::SystemResultStatus::Success;
}
@@ -117,22 +213,15 @@ extern "C" {
void Java_org_yuzu_yuzu_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env,
[[maybe_unused]] jclass clazz,
jobject surf) {
- s_surf = ANativeWindow_fromSurface(env, surf);
-
- if (emu_window) {
- emu_window->OnSurfaceChanged(s_surf);
- }
-
- LOG_INFO(Frontend, "surface changed");
+ EmulationSession::GetInstance().SetNativeWindow(ANativeWindow_fromSurface(env, surf));
+ EmulationSession::GetInstance().SurfaceChanged();
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_SurfaceDestroyed(JNIEnv* env,
[[maybe_unused]] jclass clazz) {
- ANativeWindow_release(s_surf);
- s_surf = nullptr;
- if (emu_window) {
- emu_window->OnSurfaceChanged(s_surf);
- }
+ ANativeWindow_release(EmulationSession::GetInstance().NativeWindow());
+ EmulationSession::GetInstance().SetNativeWindow(nullptr);
+ EmulationSession::GetInstance().SurfaceChanged();
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_DoFrame(JNIEnv* env, [[maybe_unused]] jclass clazz) {}
@@ -153,18 +242,22 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_PauseEmulation([[maybe_unused]] JNIEn
[[maybe_unused]] jclass clazz) {}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_StopEmulation([[maybe_unused]] JNIEnv* env,
- [[maybe_unused]] jclass clazz) {}
+ [[maybe_unused]] jclass clazz) {
+ EmulationSession::GetInstance().HaltEmulation();
+}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_IsRunning([[maybe_unused]] JNIEnv* env,
[[maybe_unused]] jclass clazz) {
- return static_cast<jboolean>(!stop_run);
+ return static_cast<jboolean>(EmulationSession::GetInstance().IsRunning());
}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadEvent([[maybe_unused]] JNIEnv* env,
[[maybe_unused]] jclass clazz,
[[maybe_unused]] jstring j_device,
jint j_button, jint action) {
- emu_window->OnGamepadEvent(j_button, action != 0);
+ if (EmulationSession::GetInstance().IsRunning()) {
+ EmulationSession::GetInstance().Window().OnGamepadEvent(j_button, action != 0);
+ }
return static_cast<jboolean>(true);
}
@@ -183,7 +276,10 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMoveEvent([[maybe_unused
x /= r;
y /= r;
}
- emu_window->OnGamepadMoveEvent(x, y);
+
+ if (EmulationSession::GetInstance().IsRunning()) {
+ EmulationSession::GetInstance().Window().OnGamepadMoveEvent(x, y);
+ }
return static_cast<jboolean>(false);
}
@@ -198,13 +294,18 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchEvent([[maybe_unused]] JNI
[[maybe_unused]] jclass clazz,
jfloat x, jfloat y,
jboolean pressed) {
- return static_cast<jboolean>(emu_window->OnTouchEvent(x, y, pressed));
+ if (EmulationSession::GetInstance().IsRunning()) {
+ return static_cast<jboolean>(EmulationSession::GetInstance().Window().OnTouchEvent(x, y, pressed));
+ }
+ return static_cast<jboolean>(false);
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved([[maybe_unused]] JNIEnv* env,
[[maybe_unused]] jclass clazz, jfloat x,
jfloat y) {
- emu_window->OnTouchMoved(x, y);
+ if (EmulationSession::GetInstance().IsRunning()) {
+ EmulationSession::GetInstance().Window().OnTouchMoved(x, y);
+ }
}
jintArray Java_org_yuzu_yuzu_1emu_NativeLibrary_GetIcon([[maybe_unused]] JNIEnv* env,
@@ -309,8 +410,8 @@ jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_GetPerfStats([[maybe_unused]]
[[maybe_unused]] jclass clazz) {
jdoubleArray j_stats = env->NewDoubleArray(4);
- if (!stop_run && system_.IsPoweredOn()) {
- const auto results = system_.GetAndResetPerfStats();
+ if (EmulationSession::GetInstance().IsRunning()) {
+ const auto results = EmulationSession::GetInstance().PerfStats();
// Converting the structure into an array makes it easier to pass it to the frontend
double stats[4] = {results.system_fps, results.average_game_fps, results.frametime,
@@ -330,10 +431,6 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_Run__Ljava_lang_String_2([[maybe_unus
jstring j_path) {
const std::string path = GetJString(env, j_path);
- if (!stop_run) {
- stop_run = true;
- }
-
const Core::SystemResultStatus result{RunEmulation(path)};
if (result != Core::SystemResultStatus::Success) {
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),