native.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <codecvt>
  4. #include <locale>
  5. #include <string>
  6. #include <string_view>
  7. #include <dlfcn.h>
  8. #ifdef ARCHITECTURE_arm64
  9. #include <adrenotools/driver.h>
  10. #endif
  11. #include <android/api-level.h>
  12. #include <android/native_window_jni.h>
  13. #include "common/detached_tasks.h"
  14. #include "common/dynamic_library.h"
  15. #include "common/fs/path_util.h"
  16. #include "common/logging/backend.h"
  17. #include "common/logging/log.h"
  18. #include "common/microprofile.h"
  19. #include "common/scm_rev.h"
  20. #include "common/scope_exit.h"
  21. #include "common/settings.h"
  22. #include "common/string_util.h"
  23. #include "core/core.h"
  24. #include "core/cpu_manager.h"
  25. #include "core/crypto/key_manager.h"
  26. #include "core/file_sys/registered_cache.h"
  27. #include "core/file_sys/vfs_real.h"
  28. #include "core/frontend/applets/cabinet.h"
  29. #include "core/frontend/applets/controller.h"
  30. #include "core/frontend/applets/error.h"
  31. #include "core/frontend/applets/general_frontend.h"
  32. #include "core/frontend/applets/mii_edit.h"
  33. #include "core/frontend/applets/profile_select.h"
  34. #include "core/frontend/applets/software_keyboard.h"
  35. #include "core/frontend/applets/web_browser.h"
  36. #include "core/hid/hid_core.h"
  37. #include "core/hle/service/am/applet_ae.h"
  38. #include "core/hle/service/am/applet_oe.h"
  39. #include "core/hle/service/am/applets/applets.h"
  40. #include "core/hle/service/filesystem/filesystem.h"
  41. #include "core/loader/loader.h"
  42. #include "core/perf_stats.h"
  43. #include "jni/android_common/android_common.h"
  44. #include "jni/applets/software_keyboard.h"
  45. #include "jni/config.h"
  46. #include "jni/emu_window/emu_window.h"
  47. #include "jni/id_cache.h"
  48. #include "video_core/rasterizer_interface.h"
  49. namespace {
  50. class EmulationSession final {
  51. public:
  52. EmulationSession() {
  53. m_vfs = std::make_shared<FileSys::RealVfsFilesystem>();
  54. }
  55. ~EmulationSession() = default;
  56. static EmulationSession& GetInstance() {
  57. return s_instance;
  58. }
  59. const Core::System& System() const {
  60. return m_system;
  61. }
  62. Core::System& System() {
  63. return m_system;
  64. }
  65. const EmuWindow_Android& Window() const {
  66. return *m_window;
  67. }
  68. EmuWindow_Android& Window() {
  69. return *m_window;
  70. }
  71. ANativeWindow* NativeWindow() const {
  72. return m_native_window;
  73. }
  74. void SetNativeWindow(ANativeWindow* m_native_window_) {
  75. m_native_window = m_native_window_;
  76. }
  77. void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir,
  78. const std::string& custom_driver_name,
  79. const std::string& file_redirect_dir) {
  80. #ifdef ARCHITECTURE_arm64
  81. void* handle{};
  82. const char* file_redirect_dir_{};
  83. int featureFlags{};
  84. // Enable driver file redirection when renderer debugging is enabled.
  85. if (Settings::values.renderer_debug && file_redirect_dir.size()) {
  86. featureFlags |= ADRENOTOOLS_DRIVER_FILE_REDIRECT;
  87. file_redirect_dir_ = file_redirect_dir.c_str();
  88. }
  89. // Try to load a custom driver.
  90. if (custom_driver_name.size()) {
  91. handle = adrenotools_open_libvulkan(
  92. RTLD_NOW, featureFlags | ADRENOTOOLS_DRIVER_CUSTOM, nullptr, hook_lib_dir.c_str(),
  93. custom_driver_dir.c_str(), custom_driver_name.c_str(), file_redirect_dir_, nullptr);
  94. }
  95. // Try to load the system driver.
  96. if (!handle) {
  97. handle =
  98. adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(),
  99. nullptr, nullptr, file_redirect_dir_, nullptr);
  100. }
  101. m_vulkan_library = std::make_shared<Common::DynamicLibrary>(handle);
  102. #endif
  103. }
  104. bool IsRunning() const {
  105. std::scoped_lock lock(m_mutex);
  106. return m_is_running;
  107. }
  108. const Core::PerfStatsResults& PerfStats() const {
  109. std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex);
  110. return m_perf_stats;
  111. }
  112. void SurfaceChanged() {
  113. if (!IsRunning()) {
  114. return;
  115. }
  116. m_window->OnSurfaceChanged(m_native_window);
  117. }
  118. Core::SystemResultStatus InitializeEmulation(const std::string& filepath) {
  119. std::scoped_lock lock(m_mutex);
  120. // Loads the configuration.
  121. Config{};
  122. // Create the render window.
  123. m_window = std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window,
  124. m_vulkan_library);
  125. // Initialize system.
  126. auto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>();
  127. m_software_keyboard = android_keyboard.get();
  128. m_system.SetShuttingDown(false);
  129. m_system.ApplySettings();
  130. m_system.HIDCore().ReloadInputDevices();
  131. m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
  132. m_system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
  133. m_system.SetAppletFrontendSet({
  134. nullptr, // Amiibo Settings
  135. nullptr, // Controller Selector
  136. nullptr, // Error Display
  137. nullptr, // Mii Editor
  138. nullptr, // Parental Controls
  139. nullptr, // Photo Viewer
  140. nullptr, // Profile Selector
  141. std::move(android_keyboard), // Software Keyboard
  142. nullptr, // Web Browser
  143. });
  144. m_system.GetFileSystemController().CreateFactories(*m_system.GetFilesystem());
  145. // Load the ROM.
  146. m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath);
  147. if (m_load_result != Core::SystemResultStatus::Success) {
  148. return m_load_result;
  149. }
  150. // Complete initialization.
  151. m_system.GPU().Start();
  152. m_system.GetCpuManager().OnGpuReady();
  153. m_system.RegisterExitCallback([&] { HaltEmulation(); });
  154. return Core::SystemResultStatus::Success;
  155. }
  156. void ShutdownEmulation() {
  157. std::scoped_lock lock(m_mutex);
  158. m_is_running = false;
  159. // Unload user input.
  160. m_system.HIDCore().UnloadInputDevices();
  161. // Shutdown the main emulated process
  162. if (m_load_result == Core::SystemResultStatus::Success) {
  163. m_system.DetachDebugger();
  164. m_system.ShutdownMainProcess();
  165. m_detached_tasks.WaitForAllTasks();
  166. m_load_result = Core::SystemResultStatus::ErrorNotInitialized;
  167. }
  168. // Tear down the render window.
  169. m_window.reset();
  170. }
  171. void PauseEmulation() {
  172. std::scoped_lock lock(m_mutex);
  173. m_system.Pause();
  174. }
  175. void UnPauseEmulation() {
  176. std::scoped_lock lock(m_mutex);
  177. m_system.Run();
  178. }
  179. void HaltEmulation() {
  180. std::scoped_lock lock(m_mutex);
  181. m_is_running = false;
  182. m_cv.notify_one();
  183. }
  184. void RunEmulation() {
  185. {
  186. std::scoped_lock lock(m_mutex);
  187. m_is_running = true;
  188. }
  189. void(m_system.Run());
  190. if (m_system.DebuggerEnabled()) {
  191. m_system.InitializeDebugger();
  192. }
  193. while (true) {
  194. {
  195. std::unique_lock lock(m_mutex);
  196. if (m_cv.wait_for(lock, std::chrono::milliseconds(800),
  197. [&]() { return !m_is_running; })) {
  198. // Emulation halted.
  199. break;
  200. }
  201. }
  202. {
  203. // Refresh performance stats.
  204. std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex);
  205. m_perf_stats = m_system.GetAndResetPerfStats();
  206. }
  207. }
  208. }
  209. std::string GetRomTitle(const std::string& path) {
  210. return GetRomMetadata(path).title;
  211. }
  212. std::vector<u8> GetRomIcon(const std::string& path) {
  213. return GetRomMetadata(path).icon;
  214. }
  215. void ResetRomMetadata() {
  216. m_rom_metadata_cache.clear();
  217. }
  218. SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard() {
  219. return m_software_keyboard;
  220. }
  221. private:
  222. struct RomMetadata {
  223. std::string title;
  224. std::vector<u8> icon;
  225. };
  226. RomMetadata GetRomMetadata(const std::string& path) {
  227. if (auto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) {
  228. return search->second;
  229. }
  230. return CacheRomMetadata(path);
  231. }
  232. RomMetadata CacheRomMetadata(const std::string& path) {
  233. const auto file = Core::GetGameFileFromPath(m_vfs, path);
  234. const auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
  235. RomMetadata entry;
  236. loader->ReadTitle(entry.title);
  237. loader->ReadIcon(entry.icon);
  238. m_rom_metadata_cache[path] = entry;
  239. return entry;
  240. }
  241. private:
  242. static EmulationSession s_instance;
  243. // Frontend management
  244. std::unordered_map<std::string, RomMetadata> m_rom_metadata_cache;
  245. // Window management
  246. std::unique_ptr<EmuWindow_Android> m_window;
  247. ANativeWindow* m_native_window{};
  248. // Core emulation
  249. Core::System m_system;
  250. InputCommon::InputSubsystem m_input_subsystem;
  251. Common::DetachedTasks m_detached_tasks;
  252. Core::PerfStatsResults m_perf_stats{};
  253. std::shared_ptr<FileSys::RealVfsFilesystem> m_vfs;
  254. Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
  255. bool m_is_running{};
  256. SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
  257. // GPU driver parameters
  258. std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
  259. // Synchronization
  260. std::condition_variable_any m_cv;
  261. mutable std::mutex m_perf_stats_mutex;
  262. mutable std::mutex m_mutex;
  263. };
  264. /*static*/ EmulationSession EmulationSession::s_instance;
  265. } // Anonymous namespace
  266. static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
  267. Common::Log::Initialize();
  268. Common::Log::SetColorConsoleBackendEnabled(true);
  269. Common::Log::Start();
  270. MicroProfileOnThreadCreate("EmuThread");
  271. SCOPE_EXIT({ MicroProfileShutdown(); });
  272. LOG_INFO(Frontend, "starting");
  273. if (filepath.empty()) {
  274. LOG_CRITICAL(Frontend, "failed to load: filepath empty!");
  275. return Core::SystemResultStatus::ErrorLoader;
  276. }
  277. SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); });
  278. const auto result = EmulationSession::GetInstance().InitializeEmulation(filepath);
  279. if (result != Core::SystemResultStatus::Success) {
  280. return result;
  281. }
  282. EmulationSession::GetInstance().RunEmulation();
  283. return Core::SystemResultStatus::Success;
  284. }
  285. extern "C" {
  286. void Java_org_yuzu_yuzu_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env,
  287. [[maybe_unused]] jclass clazz,
  288. jobject surf) {
  289. EmulationSession::GetInstance().SetNativeWindow(ANativeWindow_fromSurface(env, surf));
  290. EmulationSession::GetInstance().SurfaceChanged();
  291. }
  292. void Java_org_yuzu_yuzu_1emu_NativeLibrary_SurfaceDestroyed(JNIEnv* env,
  293. [[maybe_unused]] jclass clazz) {
  294. ANativeWindow_release(EmulationSession::GetInstance().NativeWindow());
  295. EmulationSession::GetInstance().SetNativeWindow(nullptr);
  296. EmulationSession::GetInstance().SurfaceChanged();
  297. }
  298. void Java_org_yuzu_yuzu_1emu_NativeLibrary_DoFrame(JNIEnv* env, [[maybe_unused]] jclass clazz) {}
  299. void Java_org_yuzu_yuzu_1emu_NativeLibrary_NotifyOrientationChange(JNIEnv* env,
  300. [[maybe_unused]] jclass clazz,
  301. jint layout_option,
  302. jint rotation) {}
  303. void Java_org_yuzu_yuzu_1emu_NativeLibrary_SetAppDirectory(JNIEnv* env,
  304. [[maybe_unused]] jclass clazz,
  305. jstring j_directory) {
  306. Common::FS::SetAppDirectory(GetJString(env, j_directory));
  307. }
  308. void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_InitializeGpuDriver(
  309. JNIEnv* env, [[maybe_unused]] jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir,
  310. jstring custom_driver_name, jstring file_redirect_dir) {
  311. EmulationSession::GetInstance().InitializeGpuDriver(
  312. GetJString(env, hook_lib_dir), GetJString(env, custom_driver_dir),
  313. GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir));
  314. }
  315. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_ReloadKeys(JNIEnv* env,
  316. [[maybe_unused]] jclass clazz) {
  317. Core::Crypto::KeyManager::Instance().ReloadKeys();
  318. return static_cast<jboolean>(Core::Crypto::KeyManager::Instance().AreKeysLoaded());
  319. }
  320. void Java_org_yuzu_yuzu_1emu_NativeLibrary_UnPauseEmulation([[maybe_unused]] JNIEnv* env,
  321. [[maybe_unused]] jclass clazz) {
  322. EmulationSession::GetInstance().UnPauseEmulation();
  323. }
  324. void Java_org_yuzu_yuzu_1emu_NativeLibrary_PauseEmulation([[maybe_unused]] JNIEnv* env,
  325. [[maybe_unused]] jclass clazz) {
  326. EmulationSession::GetInstance().PauseEmulation();
  327. }
  328. void Java_org_yuzu_yuzu_1emu_NativeLibrary_StopEmulation([[maybe_unused]] JNIEnv* env,
  329. [[maybe_unused]] jclass clazz) {
  330. EmulationSession::GetInstance().HaltEmulation();
  331. }
  332. void Java_org_yuzu_yuzu_1emu_NativeLibrary_ResetRomMetadata([[maybe_unused]] JNIEnv* env,
  333. [[maybe_unused]] jclass clazz) {
  334. EmulationSession::GetInstance().ResetRomMetadata();
  335. }
  336. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_IsRunning([[maybe_unused]] JNIEnv* env,
  337. [[maybe_unused]] jclass clazz) {
  338. return static_cast<jboolean>(EmulationSession::GetInstance().IsRunning());
  339. }
  340. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent([[maybe_unused]] JNIEnv* env,
  341. [[maybe_unused]] jclass clazz,
  342. [[maybe_unused]] jint j_device,
  343. jint j_button, jint action) {
  344. if (EmulationSession::GetInstance().IsRunning()) {
  345. EmulationSession::GetInstance().Window().OnGamepadButtonEvent(j_device, j_button,
  346. action != 0);
  347. }
  348. return static_cast<jboolean>(true);
  349. }
  350. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadJoystickEvent([[maybe_unused]] JNIEnv* env,
  351. [[maybe_unused]] jclass clazz,
  352. jint j_device, jint stick_id,
  353. jfloat x, jfloat y) {
  354. if (EmulationSession::GetInstance().IsRunning()) {
  355. EmulationSession::GetInstance().Window().OnGamepadJoystickEvent(j_device, stick_id, x, y);
  356. }
  357. return static_cast<jboolean>(true);
  358. }
  359. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent(
  360. [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device,
  361. jlong delta_timestamp, jfloat gyro_x, jfloat gyro_y, jfloat gyro_z, jfloat accel_x,
  362. jfloat accel_y, jfloat accel_z) {
  363. if (EmulationSession::GetInstance().IsRunning()) {
  364. EmulationSession::GetInstance().Window().OnGamepadMotionEvent(
  365. j_device, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z);
  366. }
  367. return static_cast<jboolean>(true);
  368. }
  369. void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchPressed([[maybe_unused]] JNIEnv* env,
  370. [[maybe_unused]] jclass clazz, jint id,
  371. jfloat x, jfloat y) {
  372. if (EmulationSession::GetInstance().IsRunning()) {
  373. EmulationSession::GetInstance().Window().OnTouchPressed(id, x, y);
  374. }
  375. }
  376. void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved([[maybe_unused]] JNIEnv* env,
  377. [[maybe_unused]] jclass clazz, jint id,
  378. jfloat x, jfloat y) {
  379. if (EmulationSession::GetInstance().IsRunning()) {
  380. EmulationSession::GetInstance().Window().OnTouchMoved(id, x, y);
  381. }
  382. }
  383. void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased([[maybe_unused]] JNIEnv* env,
  384. [[maybe_unused]] jclass clazz, jint id) {
  385. if (EmulationSession::GetInstance().IsRunning()) {
  386. EmulationSession::GetInstance().Window().OnTouchReleased(id);
  387. }
  388. }
  389. jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_GetIcon([[maybe_unused]] JNIEnv* env,
  390. [[maybe_unused]] jclass clazz,
  391. [[maybe_unused]] jstring j_filename) {
  392. auto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename));
  393. jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size()));
  394. env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon),
  395. reinterpret_cast<jbyte*>(icon_data.data()));
  396. return icon;
  397. }
  398. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetTitle([[maybe_unused]] JNIEnv* env,
  399. [[maybe_unused]] jclass clazz,
  400. [[maybe_unused]] jstring j_filename) {
  401. auto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename));
  402. return env->NewStringUTF(title.c_str());
  403. }
  404. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetDescription([[maybe_unused]] JNIEnv* env,
  405. [[maybe_unused]] jclass clazz,
  406. jstring j_filename) {
  407. return j_filename;
  408. }
  409. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetGameId([[maybe_unused]] JNIEnv* env,
  410. [[maybe_unused]] jclass clazz,
  411. jstring j_filename) {
  412. return j_filename;
  413. }
  414. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetRegions([[maybe_unused]] JNIEnv* env,
  415. [[maybe_unused]] jclass clazz,
  416. [[maybe_unused]] jstring j_filename) {
  417. return env->NewStringUTF("");
  418. }
  419. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetCompany([[maybe_unused]] JNIEnv* env,
  420. [[maybe_unused]] jclass clazz,
  421. [[maybe_unused]] jstring j_filename) {
  422. return env->NewStringUTF("");
  423. }
  424. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetGitRevision([[maybe_unused]] JNIEnv* env,
  425. [[maybe_unused]] jclass clazz) {
  426. return {};
  427. }
  428. void Java_org_yuzu_yuzu_1emu_NativeLibrary_InitializeEmulation
  429. [[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) {
  430. // Create the default config.ini.
  431. Config{};
  432. // Initialize the emulated system.
  433. EmulationSession::GetInstance().System().Initialize();
  434. }
  435. jint Java_org_yuzu_yuzu_1emu_NativeLibrary_DefaultCPUCore([[maybe_unused]] JNIEnv* env,
  436. [[maybe_unused]] jclass clazz) {
  437. return {};
  438. }
  439. void Java_org_yuzu_yuzu_1emu_NativeLibrary_Run__Ljava_lang_String_2Ljava_lang_String_2Z(
  440. [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, [[maybe_unused]] jstring j_file,
  441. [[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {}
  442. void Java_org_yuzu_yuzu_1emu_NativeLibrary_ReloadSettings([[maybe_unused]] JNIEnv* env,
  443. [[maybe_unused]] jclass clazz) {
  444. Config{};
  445. }
  446. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetUserSetting([[maybe_unused]] JNIEnv* env,
  447. [[maybe_unused]] jclass clazz,
  448. jstring j_game_id, jstring j_section,
  449. jstring j_key) {
  450. std::string_view game_id = env->GetStringUTFChars(j_game_id, 0);
  451. std::string_view section = env->GetStringUTFChars(j_section, 0);
  452. std::string_view key = env->GetStringUTFChars(j_key, 0);
  453. env->ReleaseStringUTFChars(j_game_id, game_id.data());
  454. env->ReleaseStringUTFChars(j_section, section.data());
  455. env->ReleaseStringUTFChars(j_key, key.data());
  456. return env->NewStringUTF("");
  457. }
  458. void Java_org_yuzu_yuzu_1emu_NativeLibrary_SetUserSetting([[maybe_unused]] JNIEnv* env,
  459. [[maybe_unused]] jclass clazz,
  460. jstring j_game_id, jstring j_section,
  461. jstring j_key, jstring j_value) {
  462. std::string_view game_id = env->GetStringUTFChars(j_game_id, 0);
  463. std::string_view section = env->GetStringUTFChars(j_section, 0);
  464. std::string_view key = env->GetStringUTFChars(j_key, 0);
  465. std::string_view value = env->GetStringUTFChars(j_value, 0);
  466. env->ReleaseStringUTFChars(j_game_id, game_id.data());
  467. env->ReleaseStringUTFChars(j_section, section.data());
  468. env->ReleaseStringUTFChars(j_key, key.data());
  469. env->ReleaseStringUTFChars(j_value, value.data());
  470. }
  471. void Java_org_yuzu_yuzu_1emu_NativeLibrary_InitGameIni([[maybe_unused]] JNIEnv* env,
  472. [[maybe_unused]] jclass clazz,
  473. jstring j_game_id) {
  474. std::string_view game_id = env->GetStringUTFChars(j_game_id, 0);
  475. env->ReleaseStringUTFChars(j_game_id, game_id.data());
  476. }
  477. jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_GetPerfStats([[maybe_unused]] JNIEnv* env,
  478. [[maybe_unused]] jclass clazz) {
  479. jdoubleArray j_stats = env->NewDoubleArray(4);
  480. if (EmulationSession::GetInstance().IsRunning()) {
  481. const auto results = EmulationSession::GetInstance().PerfStats();
  482. // Converting the structure into an array makes it easier to pass it to the frontend
  483. double stats[4] = {results.system_fps, results.average_game_fps, results.frametime,
  484. results.emulation_speed};
  485. env->SetDoubleArrayRegion(j_stats, 0, 4, stats);
  486. }
  487. return j_stats;
  488. }
  489. void Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_SetSysDirectory(
  490. [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jstring j_path) {}
  491. void Java_org_yuzu_yuzu_1emu_NativeLibrary_Run__Ljava_lang_String_2([[maybe_unused]] JNIEnv* env,
  492. [[maybe_unused]] jclass clazz,
  493. jstring j_path) {
  494. const std::string path = GetJString(env, j_path);
  495. const Core::SystemResultStatus result{RunEmulation(path)};
  496. if (result != Core::SystemResultStatus::Success) {
  497. env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),
  498. IDCache::GetExitEmulationActivity(), static_cast<int>(result));
  499. }
  500. }
  501. void Java_org_yuzu_yuzu_1emu_NativeLibrary_LogDeviceInfo([[maybe_unused]] JNIEnv* env,
  502. [[maybe_unused]] jclass clazz) {
  503. LOG_INFO(Frontend, "yuzu Version: {}-{}", Common::g_scm_branch, Common::g_scm_desc);
  504. LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level());
  505. }
  506. void Java_org_yuzu_yuzu_1emu_NativeLibrary_SubmitInlineKeyboardText(JNIEnv* env, jclass clazz,
  507. jstring j_text) {
  508. const std::u16string input = Common::UTF8ToUTF16(GetJString(env, j_text));
  509. EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardText(input);
  510. }
  511. void Java_org_yuzu_yuzu_1emu_NativeLibrary_SubmitInlineKeyboardInput(JNIEnv* env, jclass clazz,
  512. jint j_key_code) {
  513. EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardInput(j_key_code);
  514. }
  515. } // extern "C"