diff options
Diffstat (limited to '')
| -rw-r--r-- | src/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/CMakeLists.txt | 15 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/emu_window/emu_window.cpp | 58 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/emu_window/emu_window.h | 51 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/id_cache.cpp | 36 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/id_cache.h | 11 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/native.cpp | 342 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/native.h | 127 |
8 files changed, 645 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5e3a74c0f..55b113297 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt | |||
| @@ -195,3 +195,8 @@ endif() | |||
| 195 | if (ENABLE_WEB_SERVICE) | 195 | if (ENABLE_WEB_SERVICE) |
| 196 | add_subdirectory(web_service) | 196 | add_subdirectory(web_service) |
| 197 | endif() | 197 | endif() |
| 198 | |||
| 199 | if (ANDROID) | ||
| 200 | add_subdirectory(android/app/src/main/jni) | ||
| 201 | target_include_directories(yuzu-android PRIVATE android/app/src/main) | ||
| 202 | endif() | ||
diff --git a/src/android/app/src/main/jni/CMakeLists.txt b/src/android/app/src/main/jni/CMakeLists.txt new file mode 100644 index 000000000..373c0e8bd --- /dev/null +++ b/src/android/app/src/main/jni/CMakeLists.txt | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | add_library(yuzu-android SHARED | ||
| 2 | emu_window/emu_window.cpp | ||
| 3 | emu_window/emu_window.h | ||
| 4 | id_cache.cpp | ||
| 5 | id_cache.h | ||
| 6 | native.cpp | ||
| 7 | native.h | ||
| 8 | ) | ||
| 9 | |||
| 10 | set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR}) | ||
| 11 | |||
| 12 | target_link_libraries(yuzu-android PRIVATE audio_core common core input_common) | ||
| 13 | target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad inih jnigraphics log) | ||
| 14 | |||
| 15 | set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} yuzu-android) | ||
diff --git a/src/android/app/src/main/jni/emu_window/emu_window.cpp b/src/android/app/src/main/jni/emu_window/emu_window.cpp new file mode 100644 index 000000000..9062c0ae3 --- /dev/null +++ b/src/android/app/src/main/jni/emu_window/emu_window.cpp | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | #include <android/native_window_jni.h> | ||
| 2 | |||
| 3 | #include "common/logging/log.h" | ||
| 4 | #include "input_common/drivers/touch_screen.h" | ||
| 5 | #include "input_common/drivers/virtual_gamepad.h" | ||
| 6 | #include "input_common/main.h" | ||
| 7 | #include "jni/emu_window/emu_window.h" | ||
| 8 | |||
| 9 | void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { | ||
| 10 | render_window = surface; | ||
| 11 | } | ||
| 12 | |||
| 13 | bool EmuWindow_Android::OnTouchEvent(float x, float y, bool pressed) { | ||
| 14 | if (pressed) { | ||
| 15 | input_subsystem->GetTouchScreen()->TouchPressed(NormalizeX(x), NormalizeY(y), 0); | ||
| 16 | return true; | ||
| 17 | } | ||
| 18 | |||
| 19 | input_subsystem->GetTouchScreen()->ReleaseAllTouch(); | ||
| 20 | return true; | ||
| 21 | } | ||
| 22 | |||
| 23 | void EmuWindow_Android::OnTouchMoved(float x, float y) { | ||
| 24 | input_subsystem->GetTouchScreen()->TouchMoved(NormalizeX(x), NormalizeY(y), 0); | ||
| 25 | } | ||
| 26 | |||
| 27 | void EmuWindow_Android::OnGamepadEvent(int button_id, bool pressed) { | ||
| 28 | input_subsystem->GetVirtualGamepad()->SetButtonState(0, button_id, pressed); | ||
| 29 | } | ||
| 30 | |||
| 31 | void EmuWindow_Android::OnGamepadMoveEvent(float x, float y) { | ||
| 32 | input_subsystem->GetVirtualGamepad()->SetStickPosition( | ||
| 33 | 0, InputCommon::VirtualGamepad::VirtualStick::Left, x, y); | ||
| 34 | } | ||
| 35 | |||
| 36 | EmuWindow_Android::EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem_, | ||
| 37 | ANativeWindow* surface_) | ||
| 38 | : input_subsystem{input_subsystem_} { | ||
| 39 | LOG_INFO(Frontend, "initializing"); | ||
| 40 | |||
| 41 | if (!surface_) { | ||
| 42 | LOG_CRITICAL(Frontend, "surface is nullptr"); | ||
| 43 | return; | ||
| 44 | } | ||
| 45 | |||
| 46 | window_width = ANativeWindow_getWidth(surface_); | ||
| 47 | window_height = ANativeWindow_getHeight(surface_); | ||
| 48 | |||
| 49 | host_window = surface_; | ||
| 50 | window_info.type = Core::Frontend::WindowSystemType::Android; | ||
| 51 | window_info.render_surface = reinterpret_cast<void*>(host_window); | ||
| 52 | |||
| 53 | input_subsystem->Initialize(); | ||
| 54 | } | ||
| 55 | |||
| 56 | EmuWindow_Android::~EmuWindow_Android() { | ||
| 57 | input_subsystem->Shutdown(); | ||
| 58 | } | ||
diff --git a/src/android/app/src/main/jni/emu_window/emu_window.h b/src/android/app/src/main/jni/emu_window/emu_window.h new file mode 100644 index 000000000..4af51c517 --- /dev/null +++ b/src/android/app/src/main/jni/emu_window/emu_window.h | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include "core/frontend/emu_window.h" | ||
| 4 | #include "input_common/main.h" | ||
| 5 | |||
| 6 | struct ANativeWindow; | ||
| 7 | |||
| 8 | class SharedContext_Android : public Core::Frontend::GraphicsContext { | ||
| 9 | public: | ||
| 10 | SharedContext_Android() = default; | ||
| 11 | ~SharedContext_Android() = default; | ||
| 12 | void MakeCurrent() override {} | ||
| 13 | void DoneCurrent() override {} | ||
| 14 | }; | ||
| 15 | |||
| 16 | class EmuWindow_Android : public Core::Frontend::EmuWindow { | ||
| 17 | public: | ||
| 18 | EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem_, ANativeWindow* surface_); | ||
| 19 | ~EmuWindow_Android(); | ||
| 20 | |||
| 21 | void OnSurfaceChanged(ANativeWindow* surface); | ||
| 22 | bool OnTouchEvent(float x, float y, bool pressed); | ||
| 23 | void OnTouchMoved(float x, float y); | ||
| 24 | void OnGamepadEvent(int button, bool pressed); | ||
| 25 | void OnGamepadMoveEvent(float x, float y); | ||
| 26 | void OnFrameDisplayed() override {} | ||
| 27 | |||
| 28 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override { | ||
| 29 | return {std::make_unique<SharedContext_Android>()}; | ||
| 30 | } | ||
| 31 | bool IsShown() const override { | ||
| 32 | return true; | ||
| 33 | }; | ||
| 34 | |||
| 35 | private: | ||
| 36 | float NormalizeX(float x) const { | ||
| 37 | return std::clamp(x / window_width, 0.f, 1.f); | ||
| 38 | } | ||
| 39 | |||
| 40 | float NormalizeY(float y) const { | ||
| 41 | return std::clamp(y / window_height, 0.f, 1.f); | ||
| 42 | } | ||
| 43 | |||
| 44 | InputCommon::InputSubsystem* input_subsystem{}; | ||
| 45 | |||
| 46 | ANativeWindow* render_window{}; | ||
| 47 | ANativeWindow* host_window{}; | ||
| 48 | |||
| 49 | float window_width{}; | ||
| 50 | float window_height{}; | ||
| 51 | }; | ||
diff --git a/src/android/app/src/main/jni/id_cache.cpp b/src/android/app/src/main/jni/id_cache.cpp new file mode 100644 index 000000000..2955122be --- /dev/null +++ b/src/android/app/src/main/jni/id_cache.cpp | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | #include "jni/id_cache.h" | ||
| 2 | |||
| 3 | static JavaVM* s_java_vm; | ||
| 4 | static jclass s_native_library_class; | ||
| 5 | static jmethodID s_exit_emulation_activity; | ||
| 6 | |||
| 7 | namespace IDCache { | ||
| 8 | |||
| 9 | JNIEnv* GetEnvForThread() { | ||
| 10 | thread_local static struct OwnedEnv { | ||
| 11 | OwnedEnv() { | ||
| 12 | status = s_java_vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6); | ||
| 13 | if (status == JNI_EDETACHED) | ||
| 14 | s_java_vm->AttachCurrentThread(&env, nullptr); | ||
| 15 | } | ||
| 16 | |||
| 17 | ~OwnedEnv() { | ||
| 18 | if (status == JNI_EDETACHED) | ||
| 19 | s_java_vm->DetachCurrentThread(); | ||
| 20 | } | ||
| 21 | |||
| 22 | int status; | ||
| 23 | JNIEnv* env = nullptr; | ||
| 24 | } owned; | ||
| 25 | return owned.env; | ||
| 26 | } | ||
| 27 | |||
| 28 | jclass GetNativeLibraryClass() { | ||
| 29 | return s_native_library_class; | ||
| 30 | } | ||
| 31 | |||
| 32 | jmethodID GetExitEmulationActivity() { | ||
| 33 | return s_exit_emulation_activity; | ||
| 34 | } | ||
| 35 | |||
| 36 | } // namespace IDCache | ||
diff --git a/src/android/app/src/main/jni/id_cache.h b/src/android/app/src/main/jni/id_cache.h new file mode 100644 index 000000000..2fe07169d --- /dev/null +++ b/src/android/app/src/main/jni/id_cache.h | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <jni.h> | ||
| 4 | |||
| 5 | namespace IDCache { | ||
| 6 | |||
| 7 | JNIEnv* GetEnvForThread(); | ||
| 8 | jclass GetNativeLibraryClass(); | ||
| 9 | jmethodID GetExitEmulationActivity(); | ||
| 10 | |||
| 11 | } // namespace IDCache | ||
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp new file mode 100644 index 000000000..b343a1453 --- /dev/null +++ b/src/android/app/src/main/jni/native.cpp | |||
| @@ -0,0 +1,342 @@ | |||
| 1 | #include <codecvt> | ||
| 2 | #include <locale> | ||
| 3 | #include <string> | ||
| 4 | #include <string_view> | ||
| 5 | |||
| 6 | #include <android/api-level.h> | ||
| 7 | #include <android/native_window_jni.h> | ||
| 8 | |||
| 9 | #include "common/detached_tasks.h" | ||
| 10 | #include "common/logging/backend.h" | ||
| 11 | #include "common/logging/log.h" | ||
| 12 | #include "common/microprofile.h" | ||
| 13 | #include "common/scm_rev.h" | ||
| 14 | #include "common/scope_exit.h" | ||
| 15 | #include "common/settings.h" | ||
| 16 | #include "core/core.h" | ||
| 17 | #include "core/cpu_manager.h" | ||
| 18 | #include "core/file_sys/registered_cache.h" | ||
| 19 | #include "core/file_sys/vfs_real.h" | ||
| 20 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 21 | #include "core/perf_stats.h" | ||
| 22 | #include "jni/emu_window/emu_window.h" | ||
| 23 | #include "jni/id_cache.h" | ||
| 24 | #include "video_core/rasterizer_interface.h" | ||
| 25 | |||
| 26 | namespace { | ||
| 27 | |||
| 28 | ANativeWindow* s_surf{}; | ||
| 29 | std::unique_ptr<EmuWindow_Android> emu_window; | ||
| 30 | std::atomic<bool> stop_run{true}; | ||
| 31 | Core::System system_; | ||
| 32 | |||
| 33 | std::string UTF16ToUTF8(std::u16string_view input) { | ||
| 34 | std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; | ||
| 35 | return convert.to_bytes(input.data(), input.data() + input.size()); | ||
| 36 | } | ||
| 37 | |||
| 38 | std::string GetJString(JNIEnv* env, jstring jstr) { | ||
| 39 | if (!jstr) { | ||
| 40 | return {}; | ||
| 41 | } | ||
| 42 | |||
| 43 | const jchar* jchars = env->GetStringChars(jstr, nullptr); | ||
| 44 | const jsize length = env->GetStringLength(jstr); | ||
| 45 | const std::u16string_view string_view(reinterpret_cast<const char16_t*>(jchars), length); | ||
| 46 | const std::string converted_string = UTF16ToUTF8(string_view); | ||
| 47 | env->ReleaseStringChars(jstr, jchars); | ||
| 48 | |||
| 49 | return converted_string; | ||
| 50 | } | ||
| 51 | |||
| 52 | } // Anonymous namespace | ||
| 53 | |||
| 54 | static Core::SystemResultStatus RunEmulation(const std::string& filepath) { | ||
| 55 | Common::Log::Initialize(); | ||
| 56 | Common::Log::SetColorConsoleBackendEnabled(true); | ||
| 57 | Common::Log::Start(); | ||
| 58 | Common::DetachedTasks detached_tasks; | ||
| 59 | |||
| 60 | MicroProfileOnThreadCreate("EmuThread"); | ||
| 61 | SCOPE_EXIT({ MicroProfileShutdown(); }); | ||
| 62 | |||
| 63 | LOG_INFO(Frontend, "starting"); | ||
| 64 | |||
| 65 | if (filepath.empty()) { | ||
| 66 | LOG_CRITICAL(Frontend, "failed to load: filepath empty!"); | ||
| 67 | return Core::SystemResultStatus::ErrorLoader; | ||
| 68 | } | ||
| 69 | |||
| 70 | system_.Initialize(); | ||
| 71 | system_.ApplySettings(); | ||
| 72 | |||
| 73 | InputCommon::InputSubsystem input_subsystem{}; | ||
| 74 | |||
| 75 | emu_window = std::make_unique<EmuWindow_Android>(&input_subsystem, s_surf); | ||
| 76 | |||
| 77 | system_.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>()); | ||
| 78 | system_.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>()); | ||
| 79 | system_.GetFileSystemController().CreateFactories(*system_.GetFilesystem()); | ||
| 80 | |||
| 81 | const Core::SystemResultStatus load_result{system_.Load(*emu_window, filepath)}; | ||
| 82 | |||
| 83 | if (load_result != Core::SystemResultStatus::Success) { | ||
| 84 | return load_result; | ||
| 85 | } | ||
| 86 | |||
| 87 | system_.GPU().Start(); | ||
| 88 | system_.GetCpuManager().OnGpuReady(); | ||
| 89 | system_.RegisterExitCallback([&] { exit(0); }); | ||
| 90 | |||
| 91 | void(system_.Run()); | ||
| 92 | |||
| 93 | if (system_.DebuggerEnabled()) { | ||
| 94 | system_.InitializeDebugger(); | ||
| 95 | } | ||
| 96 | |||
| 97 | stop_run = false; | ||
| 98 | while (!stop_run) { | ||
| 99 | std::this_thread::sleep_for(std::chrono::seconds(1)); | ||
| 100 | } | ||
| 101 | |||
| 102 | system_.DetachDebugger(); | ||
| 103 | void(system_.Pause()); | ||
| 104 | system_.ShutdownMainProcess(); | ||
| 105 | |||
| 106 | detached_tasks.WaitForAllTasks(); | ||
| 107 | |||
| 108 | return Core::SystemResultStatus::Success; | ||
| 109 | } | ||
| 110 | |||
| 111 | extern "C" { | ||
| 112 | |||
| 113 | void Java_org_citra_citra_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env, | ||
| 114 | [[maybe_unused]] jclass clazz, | ||
| 115 | jobject surf) { | ||
| 116 | s_surf = ANativeWindow_fromSurface(env, surf); | ||
| 117 | |||
| 118 | if (emu_window) { | ||
| 119 | emu_window->OnSurfaceChanged(s_surf); | ||
| 120 | } | ||
| 121 | |||
| 122 | LOG_INFO(Frontend, "surface changed"); | ||
| 123 | } | ||
| 124 | |||
| 125 | void Java_org_citra_citra_1emu_NativeLibrary_SurfaceDestroyed(JNIEnv* env, | ||
| 126 | [[maybe_unused]] jclass clazz) { | ||
| 127 | ANativeWindow_release(s_surf); | ||
| 128 | s_surf = nullptr; | ||
| 129 | if (emu_window) { | ||
| 130 | emu_window->OnSurfaceChanged(s_surf); | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | void Java_org_citra_citra_1emu_NativeLibrary_DoFrame(JNIEnv* env, [[maybe_unused]] jclass clazz) {} | ||
| 135 | |||
| 136 | void Java_org_citra_citra_1emu_NativeLibrary_NotifyOrientationChange(JNIEnv* env, | ||
| 137 | [[maybe_unused]] jclass clazz, | ||
| 138 | jint layout_option, | ||
| 139 | jint rotation) {} | ||
| 140 | |||
| 141 | void Java_org_citra_citra_1emu_NativeLibrary_SetUserDirectory( | ||
| 142 | [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, | ||
| 143 | [[maybe_unused]] jstring j_directory) {} | ||
| 144 | |||
| 145 | void Java_org_citra_citra_1emu_NativeLibrary_UnPauseEmulation([[maybe_unused]] JNIEnv* env, | ||
| 146 | [[maybe_unused]] jclass clazz) {} | ||
| 147 | |||
| 148 | void Java_org_citra_citra_1emu_NativeLibrary_PauseEmulation([[maybe_unused]] JNIEnv* env, | ||
| 149 | [[maybe_unused]] jclass clazz) {} | ||
| 150 | |||
| 151 | void Java_org_citra_citra_1emu_NativeLibrary_StopEmulation([[maybe_unused]] JNIEnv* env, | ||
| 152 | [[maybe_unused]] jclass clazz) {} | ||
| 153 | |||
| 154 | jboolean Java_org_citra_citra_1emu_NativeLibrary_IsRunning([[maybe_unused]] JNIEnv* env, | ||
| 155 | [[maybe_unused]] jclass clazz) { | ||
| 156 | return static_cast<jboolean>(!stop_run); | ||
| 157 | } | ||
| 158 | |||
| 159 | jboolean Java_org_citra_citra_1emu_NativeLibrary_onGamePadEvent([[maybe_unused]] JNIEnv* env, | ||
| 160 | [[maybe_unused]] jclass clazz, | ||
| 161 | [[maybe_unused]] jstring j_device, | ||
| 162 | jint j_button, jint action) { | ||
| 163 | emu_window->OnGamepadEvent(j_button, action != 0); | ||
| 164 | return static_cast<jboolean>(true); | ||
| 165 | } | ||
| 166 | |||
| 167 | jboolean Java_org_citra_citra_1emu_NativeLibrary_onGamePadMoveEvent([[maybe_unused]] JNIEnv* env, | ||
| 168 | [[maybe_unused]] jclass clazz, | ||
| 169 | jstring j_device, jint axis, | ||
| 170 | jfloat x, jfloat y) { | ||
| 171 | // Clamp joystick movement to supported minimum and maximum. | ||
| 172 | x = std::clamp(x, -1.f, 1.f); | ||
| 173 | y = std::clamp(-y, -1.f, 1.f); | ||
| 174 | |||
| 175 | // Clamp the input to a circle. | ||
| 176 | float r = x * x + y * y; | ||
| 177 | if (r > 1.0f) { | ||
| 178 | r = std::sqrt(r); | ||
| 179 | x /= r; | ||
| 180 | y /= r; | ||
| 181 | } | ||
| 182 | emu_window->OnGamepadMoveEvent(x, y); | ||
| 183 | return static_cast<jboolean>(false); | ||
| 184 | } | ||
| 185 | |||
| 186 | jboolean Java_org_citra_citra_1emu_NativeLibrary_onGamePadAxisEvent([[maybe_unused]] JNIEnv* env, | ||
| 187 | [[maybe_unused]] jclass clazz, | ||
| 188 | jstring j_device, jint axis_id, | ||
| 189 | jfloat axis_val) { | ||
| 190 | return {}; | ||
| 191 | } | ||
| 192 | |||
| 193 | jboolean Java_org_citra_citra_1emu_NativeLibrary_onTouchEvent([[maybe_unused]] JNIEnv* env, | ||
| 194 | [[maybe_unused]] jclass clazz, | ||
| 195 | jfloat x, jfloat y, | ||
| 196 | jboolean pressed) { | ||
| 197 | return static_cast<jboolean>(emu_window->OnTouchEvent(x, y, pressed)); | ||
| 198 | } | ||
| 199 | |||
| 200 | void Java_org_citra_citra_1emu_NativeLibrary_onTouchMoved([[maybe_unused]] JNIEnv* env, | ||
| 201 | [[maybe_unused]] jclass clazz, jfloat x, | ||
| 202 | jfloat y) { | ||
| 203 | emu_window->OnTouchMoved(x, y); | ||
| 204 | } | ||
| 205 | |||
| 206 | jintArray Java_org_citra_citra_1emu_NativeLibrary_GetIcon([[maybe_unused]] JNIEnv* env, | ||
| 207 | [[maybe_unused]] jclass clazz, | ||
| 208 | [[maybe_unused]] jstring j_file) { | ||
| 209 | return {}; | ||
| 210 | } | ||
| 211 | |||
| 212 | jstring Java_org_citra_citra_1emu_NativeLibrary_GetTitle([[maybe_unused]] JNIEnv* env, | ||
| 213 | [[maybe_unused]] jclass clazz, | ||
| 214 | [[maybe_unused]] jstring j_filename) { | ||
| 215 | return env->NewStringUTF(""); | ||
| 216 | } | ||
| 217 | |||
| 218 | jstring Java_org_citra_citra_1emu_NativeLibrary_GetDescription([[maybe_unused]] JNIEnv* env, | ||
| 219 | [[maybe_unused]] jclass clazz, | ||
| 220 | jstring j_filename) { | ||
| 221 | return j_filename; | ||
| 222 | } | ||
| 223 | |||
| 224 | jstring Java_org_citra_citra_1emu_NativeLibrary_GetGameId([[maybe_unused]] JNIEnv* env, | ||
| 225 | [[maybe_unused]] jclass clazz, | ||
| 226 | jstring j_filename) { | ||
| 227 | return j_filename; | ||
| 228 | } | ||
| 229 | |||
| 230 | jstring Java_org_citra_citra_1emu_NativeLibrary_GetRegions([[maybe_unused]] JNIEnv* env, | ||
| 231 | [[maybe_unused]] jclass clazz, | ||
| 232 | [[maybe_unused]] jstring j_filename) { | ||
| 233 | return env->NewStringUTF(""); | ||
| 234 | } | ||
| 235 | |||
| 236 | jstring Java_org_citra_citra_1emu_NativeLibrary_GetCompany([[maybe_unused]] JNIEnv* env, | ||
| 237 | [[maybe_unused]] jclass clazz, | ||
| 238 | [[maybe_unused]] jstring j_filename) { | ||
| 239 | return env->NewStringUTF(""); | ||
| 240 | } | ||
| 241 | |||
| 242 | jstring Java_org_citra_citra_1emu_NativeLibrary_GetGitRevision([[maybe_unused]] JNIEnv* env, | ||
| 243 | [[maybe_unused]] jclass clazz) { | ||
| 244 | return {}; | ||
| 245 | } | ||
| 246 | |||
| 247 | void Java_org_citra_citra_1emu_NativeLibrary_CreateConfigFile | ||
| 248 | [[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) {} | ||
| 249 | |||
| 250 | jint Java_org_citra_citra_1emu_NativeLibrary_DefaultCPUCore([[maybe_unused]] JNIEnv* env, | ||
| 251 | [[maybe_unused]] jclass clazz) { | ||
| 252 | return {}; | ||
| 253 | } | ||
| 254 | |||
| 255 | void Java_org_citra_citra_1emu_NativeLibrary_Run__Ljava_lang_String_2Ljava_lang_String_2Z( | ||
| 256 | [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, [[maybe_unused]] jstring j_file, | ||
| 257 | [[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {} | ||
| 258 | |||
| 259 | void Java_org_citra_citra_1emu_NativeLibrary_ReloadSettings([[maybe_unused]] JNIEnv* env, | ||
| 260 | [[maybe_unused]] jclass clazz) {} | ||
| 261 | |||
| 262 | jstring Java_org_citra_citra_1emu_NativeLibrary_GetUserSetting([[maybe_unused]] JNIEnv* env, | ||
| 263 | [[maybe_unused]] jclass clazz, | ||
| 264 | jstring j_game_id, jstring j_section, | ||
| 265 | jstring j_key) { | ||
| 266 | std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); | ||
| 267 | std::string_view section = env->GetStringUTFChars(j_section, 0); | ||
| 268 | std::string_view key = env->GetStringUTFChars(j_key, 0); | ||
| 269 | |||
| 270 | env->ReleaseStringUTFChars(j_game_id, game_id.data()); | ||
| 271 | env->ReleaseStringUTFChars(j_section, section.data()); | ||
| 272 | env->ReleaseStringUTFChars(j_key, key.data()); | ||
| 273 | |||
| 274 | return env->NewStringUTF(""); | ||
| 275 | } | ||
| 276 | |||
| 277 | void Java_org_citra_citra_1emu_NativeLibrary_SetUserSetting([[maybe_unused]] JNIEnv* env, | ||
| 278 | [[maybe_unused]] jclass clazz, | ||
| 279 | jstring j_game_id, jstring j_section, | ||
| 280 | jstring j_key, jstring j_value) { | ||
| 281 | std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); | ||
| 282 | std::string_view section = env->GetStringUTFChars(j_section, 0); | ||
| 283 | std::string_view key = env->GetStringUTFChars(j_key, 0); | ||
| 284 | std::string_view value = env->GetStringUTFChars(j_value, 0); | ||
| 285 | |||
| 286 | env->ReleaseStringUTFChars(j_game_id, game_id.data()); | ||
| 287 | env->ReleaseStringUTFChars(j_section, section.data()); | ||
| 288 | env->ReleaseStringUTFChars(j_key, key.data()); | ||
| 289 | env->ReleaseStringUTFChars(j_value, value.data()); | ||
| 290 | } | ||
| 291 | |||
| 292 | void Java_org_citra_citra_1emu_NativeLibrary_InitGameIni([[maybe_unused]] JNIEnv* env, | ||
| 293 | [[maybe_unused]] jclass clazz, | ||
| 294 | jstring j_game_id) { | ||
| 295 | std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); | ||
| 296 | |||
| 297 | env->ReleaseStringUTFChars(j_game_id, game_id.data()); | ||
| 298 | } | ||
| 299 | |||
| 300 | jdoubleArray Java_org_citra_citra_1emu_NativeLibrary_GetPerfStats([[maybe_unused]] JNIEnv* env, | ||
| 301 | [[maybe_unused]] jclass clazz) { | ||
| 302 | jdoubleArray j_stats = env->NewDoubleArray(4); | ||
| 303 | |||
| 304 | if (!stop_run && system_.IsPoweredOn()) { | ||
| 305 | const auto results = system_.GetAndResetPerfStats(); | ||
| 306 | |||
| 307 | // Converting the structure into an array makes it easier to pass it to the frontend | ||
| 308 | double stats[4] = {results.system_fps, results.average_game_fps, results.frametime, | ||
| 309 | results.emulation_speed}; | ||
| 310 | |||
| 311 | env->SetDoubleArrayRegion(j_stats, 0, 4, stats); | ||
| 312 | } | ||
| 313 | |||
| 314 | return j_stats; | ||
| 315 | } | ||
| 316 | |||
| 317 | void Java_org_citra_citra_1emu_utils_DirectoryInitialization_SetSysDirectory( | ||
| 318 | [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jstring j_path) {} | ||
| 319 | |||
| 320 | void Java_org_citra_citra_1emu_NativeLibrary_Run__Ljava_lang_String_2([[maybe_unused]] JNIEnv* env, | ||
| 321 | [[maybe_unused]] jclass clazz, | ||
| 322 | jstring j_path) { | ||
| 323 | const std::string path = GetJString(env, j_path); | ||
| 324 | |||
| 325 | if (!stop_run) { | ||
| 326 | stop_run = true; | ||
| 327 | } | ||
| 328 | |||
| 329 | const Core::SystemResultStatus result{RunEmulation(path)}; | ||
| 330 | if (result != Core::SystemResultStatus::Success) { | ||
| 331 | env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), | ||
| 332 | IDCache::GetExitEmulationActivity(), static_cast<int>(result)); | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | void Java_org_citra_citra_1emu_NativeLibrary_LogDeviceInfo([[maybe_unused]] JNIEnv* env, | ||
| 337 | [[maybe_unused]] jclass clazz) { | ||
| 338 | LOG_INFO(Frontend, "yuzu Version: {}-{}", Common::g_scm_branch, Common::g_scm_desc); | ||
| 339 | LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level()); | ||
| 340 | } | ||
| 341 | |||
| 342 | } // extern "C" | ||
diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h new file mode 100644 index 000000000..16c90e215 --- /dev/null +++ b/src/android/app/src/main/jni/native.h | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <jni.h> | ||
| 4 | |||
| 5 | // Function calls from the Java side | ||
| 6 | #ifdef __cplusplus | ||
| 7 | extern "C" { | ||
| 8 | #endif | ||
| 9 | |||
| 10 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_UnPauseEmulation(JNIEnv* env, | ||
| 11 | jclass clazz); | ||
| 12 | |||
| 13 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_PauseEmulation(JNIEnv* env, | ||
| 14 | jclass clazz); | ||
| 15 | |||
| 16 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_StopEmulation(JNIEnv* env, | ||
| 17 | jclass clazz); | ||
| 18 | |||
| 19 | JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_IsRunning(JNIEnv* env, | ||
| 20 | jclass clazz); | ||
| 21 | |||
| 22 | JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_onGamePadEvent( | ||
| 23 | JNIEnv* env, jclass clazz, jstring j_device, jint j_button, jint action); | ||
| 24 | |||
| 25 | JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_onGamePadMoveEvent( | ||
| 26 | JNIEnv* env, jclass clazz, jstring j_device, jint axis, jfloat x, jfloat y); | ||
| 27 | |||
| 28 | JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_onGamePadAxisEvent( | ||
| 29 | JNIEnv* env, jclass clazz, jstring j_device, jint axis_id, jfloat axis_val); | ||
| 30 | |||
| 31 | JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_onTouchEvent(JNIEnv* env, | ||
| 32 | jclass clazz, | ||
| 33 | jfloat x, jfloat y, | ||
| 34 | jboolean pressed); | ||
| 35 | |||
| 36 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_onTouchMoved(JNIEnv* env, | ||
| 37 | jclass clazz, jfloat x, | ||
| 38 | jfloat y); | ||
| 39 | |||
| 40 | JNIEXPORT jintArray JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetIcon(JNIEnv* env, | ||
| 41 | jclass clazz, | ||
| 42 | jstring j_file); | ||
| 43 | |||
| 44 | JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetTitle(JNIEnv* env, | ||
| 45 | jclass clazz, | ||
| 46 | jstring j_filename); | ||
| 47 | |||
| 48 | JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetDescription( | ||
| 49 | JNIEnv* env, jclass clazz, jstring j_filename); | ||
| 50 | |||
| 51 | JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetGameId(JNIEnv* env, | ||
| 52 | jclass clazz, | ||
| 53 | jstring j_filename); | ||
| 54 | |||
| 55 | JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetRegions(JNIEnv* env, | ||
| 56 | jclass clazz, | ||
| 57 | jstring j_filename); | ||
| 58 | |||
| 59 | JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetCompany(JNIEnv* env, | ||
| 60 | jclass clazz, | ||
| 61 | jstring j_filename); | ||
| 62 | |||
| 63 | JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetGitRevision(JNIEnv* env, | ||
| 64 | jclass clazz); | ||
| 65 | |||
| 66 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SetUserDirectory( | ||
| 67 | JNIEnv* env, jclass clazz, jstring j_directory); | ||
| 68 | |||
| 69 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_utils_DirectoryInitialization_SetSysDirectory( | ||
| 70 | JNIEnv* env, jclass clazz, jstring path_); | ||
| 71 | |||
| 72 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SetSysDirectory(JNIEnv* env, | ||
| 73 | jclass clazz, | ||
| 74 | jstring path); | ||
| 75 | |||
| 76 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_CreateConfigFile(JNIEnv* env, | ||
| 77 | jclass clazz); | ||
| 78 | |||
| 79 | JNIEXPORT jint JNICALL Java_org_citra_citra_1emu_NativeLibrary_DefaultCPUCore(JNIEnv* env, | ||
| 80 | jclass clazz); | ||
| 81 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SetProfiling(JNIEnv* env, | ||
| 82 | jclass clazz, | ||
| 83 | jboolean enable); | ||
| 84 | |||
| 85 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_WriteProfileResults(JNIEnv* env, | ||
| 86 | jclass clazz); | ||
| 87 | |||
| 88 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_NotifyOrientationChange( | ||
| 89 | JNIEnv* env, jclass clazz, jint layout_option, jint rotation); | ||
| 90 | |||
| 91 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_Run__Ljava_lang_String_2( | ||
| 92 | JNIEnv* env, jclass clazz, jstring j_path); | ||
| 93 | |||
| 94 | JNIEXPORT void JNICALL | ||
| 95 | Java_org_citra_citra_1emu_NativeLibrary_Run__Ljava_lang_String_2Ljava_lang_String_2Z( | ||
| 96 | JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate); | ||
| 97 | |||
| 98 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env, | ||
| 99 | jclass clazz, | ||
| 100 | jobject surf); | ||
| 101 | |||
| 102 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SurfaceDestroyed(JNIEnv* env, | ||
| 103 | jclass clazz); | ||
| 104 | |||
| 105 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_InitGameIni(JNIEnv* env, | ||
| 106 | jclass clazz, | ||
| 107 | jstring j_game_id); | ||
| 108 | |||
| 109 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_ReloadSettings(JNIEnv* env, | ||
| 110 | jclass clazz); | ||
| 111 | |||
| 112 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SetUserSetting( | ||
| 113 | JNIEnv* env, jclass clazz, jstring j_game_id, jstring j_section, jstring j_key, | ||
| 114 | jstring j_value); | ||
| 115 | |||
| 116 | JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetUserSetting( | ||
| 117 | JNIEnv* env, jclass clazz, jstring game_id, jstring section, jstring key); | ||
| 118 | |||
| 119 | JNIEXPORT jdoubleArray JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetPerfStats(JNIEnv* env, | ||
| 120 | jclass clazz); | ||
| 121 | |||
| 122 | JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_LogDeviceInfo(JNIEnv* env, | ||
| 123 | jclass clazz); | ||
| 124 | |||
| 125 | #ifdef __cplusplus | ||
| 126 | } | ||
| 127 | #endif | ||