native.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884
  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 <core/loader/nro.h>
  14. #include "common/detached_tasks.h"
  15. #include "common/dynamic_library.h"
  16. #include "common/fs/path_util.h"
  17. #include "common/logging/backend.h"
  18. #include "common/logging/log.h"
  19. #include "common/microprofile.h"
  20. #include "common/scm_rev.h"
  21. #include "common/scope_exit.h"
  22. #include "common/settings.h"
  23. #include "common/string_util.h"
  24. #include "core/core.h"
  25. #include "core/cpu_manager.h"
  26. #include "core/crypto/key_manager.h"
  27. #include "core/file_sys/card_image.h"
  28. #include "core/file_sys/registered_cache.h"
  29. #include "core/file_sys/submission_package.h"
  30. #include "core/file_sys/vfs.h"
  31. #include "core/file_sys/vfs_real.h"
  32. #include "core/frontend/applets/cabinet.h"
  33. #include "core/frontend/applets/controller.h"
  34. #include "core/frontend/applets/error.h"
  35. #include "core/frontend/applets/general_frontend.h"
  36. #include "core/frontend/applets/mii_edit.h"
  37. #include "core/frontend/applets/profile_select.h"
  38. #include "core/frontend/applets/software_keyboard.h"
  39. #include "core/frontend/applets/web_browser.h"
  40. #include "core/hid/emulated_controller.h"
  41. #include "core/hid/hid_core.h"
  42. #include "core/hid/hid_types.h"
  43. #include "core/hle/service/acc/profile_manager.h"
  44. #include "core/hle/service/am/applet_ae.h"
  45. #include "core/hle/service/am/applet_oe.h"
  46. #include "core/hle/service/am/applets/applets.h"
  47. #include "core/hle/service/filesystem/filesystem.h"
  48. #include "core/loader/loader.h"
  49. #include "core/perf_stats.h"
  50. #include "jni/android_common/android_common.h"
  51. #include "jni/applets/software_keyboard.h"
  52. #include "jni/config.h"
  53. #include "jni/emu_window/emu_window.h"
  54. #include "jni/id_cache.h"
  55. #include "video_core/rasterizer_interface.h"
  56. #include "video_core/renderer_base.h"
  57. namespace {
  58. class EmulationSession final {
  59. public:
  60. EmulationSession() {
  61. m_vfs = std::make_shared<FileSys::RealVfsFilesystem>();
  62. }
  63. ~EmulationSession() = default;
  64. static EmulationSession& GetInstance() {
  65. return s_instance;
  66. }
  67. const Core::System& System() const {
  68. return m_system;
  69. }
  70. Core::System& System() {
  71. return m_system;
  72. }
  73. const EmuWindow_Android& Window() const {
  74. return *m_window;
  75. }
  76. EmuWindow_Android& Window() {
  77. return *m_window;
  78. }
  79. ANativeWindow* NativeWindow() const {
  80. return m_native_window;
  81. }
  82. void SetNativeWindow(ANativeWindow* native_window) {
  83. m_native_window = native_window;
  84. }
  85. int InstallFileToNand(std::string filename) {
  86. const auto copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest,
  87. std::size_t block_size) {
  88. if (src == nullptr || dest == nullptr) {
  89. return false;
  90. }
  91. if (!dest->Resize(src->GetSize())) {
  92. return false;
  93. }
  94. using namespace Common::Literals;
  95. std::vector<u8> buffer(1_MiB);
  96. for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
  97. const auto read = src->Read(buffer.data(), buffer.size(), i);
  98. dest->Write(buffer.data(), read, i);
  99. }
  100. return true;
  101. };
  102. enum InstallResult {
  103. Success = 0,
  104. SuccessFileOverwritten = 1,
  105. InstallError = 2,
  106. ErrorBaseGame = 3,
  107. ErrorFilenameExtension = 4,
  108. };
  109. m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
  110. m_system.GetFileSystemController().CreateFactories(*m_vfs);
  111. std::shared_ptr<FileSys::NSP> nsp;
  112. if (filename.ends_with("nsp")) {
  113. nsp = std::make_shared<FileSys::NSP>(m_vfs->OpenFile(filename, FileSys::Mode::Read));
  114. if (nsp->IsExtractedType()) {
  115. return InstallError;
  116. }
  117. } else if (filename.ends_with("xci")) {
  118. const auto xci =
  119. std::make_shared<FileSys::XCI>(m_vfs->OpenFile(filename, FileSys::Mode::Read));
  120. nsp = xci->GetSecurePartitionNSP();
  121. } else {
  122. return ErrorFilenameExtension;
  123. }
  124. if (!nsp) {
  125. return InstallError;
  126. }
  127. if (nsp->GetStatus() != Loader::ResultStatus::Success) {
  128. return InstallError;
  129. }
  130. const auto res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry(
  131. *nsp, true, copy_func);
  132. switch (res) {
  133. case FileSys::InstallResult::Success:
  134. return Success;
  135. case FileSys::InstallResult::OverwriteExisting:
  136. return SuccessFileOverwritten;
  137. case FileSys::InstallResult::ErrorBaseInstall:
  138. return ErrorBaseGame;
  139. default:
  140. return InstallError;
  141. }
  142. }
  143. void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir,
  144. const std::string& custom_driver_name,
  145. const std::string& file_redirect_dir) {
  146. #ifdef ARCHITECTURE_arm64
  147. void* handle{};
  148. const char* file_redirect_dir_{};
  149. int featureFlags{};
  150. // Enable driver file redirection when renderer debugging is enabled.
  151. if (Settings::values.renderer_debug && file_redirect_dir.size()) {
  152. featureFlags |= ADRENOTOOLS_DRIVER_FILE_REDIRECT;
  153. file_redirect_dir_ = file_redirect_dir.c_str();
  154. }
  155. // Try to load a custom driver.
  156. if (custom_driver_name.size()) {
  157. handle = adrenotools_open_libvulkan(
  158. RTLD_NOW, featureFlags | ADRENOTOOLS_DRIVER_CUSTOM, nullptr, hook_lib_dir.c_str(),
  159. custom_driver_dir.c_str(), custom_driver_name.c_str(), file_redirect_dir_, nullptr);
  160. }
  161. // Try to load the system driver.
  162. if (!handle) {
  163. handle =
  164. adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(),
  165. nullptr, nullptr, file_redirect_dir_, nullptr);
  166. }
  167. m_vulkan_library = std::make_shared<Common::DynamicLibrary>(handle);
  168. #endif
  169. }
  170. bool IsRunning() const {
  171. std::scoped_lock lock(m_mutex);
  172. return m_is_running;
  173. }
  174. bool IsPaused() const {
  175. std::scoped_lock lock(m_mutex);
  176. return m_is_running && m_is_paused;
  177. }
  178. const Core::PerfStatsResults& PerfStats() const {
  179. std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex);
  180. return m_perf_stats;
  181. }
  182. void SurfaceChanged() {
  183. if (!IsRunning()) {
  184. return;
  185. }
  186. m_window->OnSurfaceChanged(m_native_window);
  187. m_system.Renderer().NotifySurfaceChanged();
  188. }
  189. Core::SystemResultStatus InitializeEmulation(const std::string& filepath) {
  190. std::scoped_lock lock(m_mutex);
  191. // Loads the configuration.
  192. Config{};
  193. // Create the render window.
  194. m_window = std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window,
  195. m_vulkan_library);
  196. m_system.SetFilesystem(m_vfs);
  197. // Initialize system.
  198. auto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>();
  199. m_software_keyboard = android_keyboard.get();
  200. m_system.SetShuttingDown(false);
  201. m_system.ApplySettings();
  202. Settings::LogSettings();
  203. m_system.HIDCore().ReloadInputDevices();
  204. m_system.SetAppletFrontendSet({
  205. nullptr, // Amiibo Settings
  206. nullptr, // Controller Selector
  207. nullptr, // Error Display
  208. nullptr, // Mii Editor
  209. nullptr, // Parental Controls
  210. nullptr, // Photo Viewer
  211. nullptr, // Profile Selector
  212. std::move(android_keyboard), // Software Keyboard
  213. nullptr, // Web Browser
  214. });
  215. m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
  216. m_system.GetFileSystemController().CreateFactories(*m_vfs);
  217. // Initialize account manager
  218. m_profile_manager = std::make_unique<Service::Account::ProfileManager>();
  219. // Load the ROM.
  220. m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath);
  221. if (m_load_result != Core::SystemResultStatus::Success) {
  222. return m_load_result;
  223. }
  224. // Complete initialization.
  225. m_system.GPU().Start();
  226. m_system.GetCpuManager().OnGpuReady();
  227. m_system.RegisterExitCallback([&] { HaltEmulation(); });
  228. return Core::SystemResultStatus::Success;
  229. }
  230. void ShutdownEmulation() {
  231. std::scoped_lock lock(m_mutex);
  232. m_is_running = false;
  233. // Unload user input.
  234. m_system.HIDCore().UnloadInputDevices();
  235. // Shutdown the main emulated process
  236. if (m_load_result == Core::SystemResultStatus::Success) {
  237. m_system.DetachDebugger();
  238. m_system.ShutdownMainProcess();
  239. m_detached_tasks.WaitForAllTasks();
  240. m_load_result = Core::SystemResultStatus::ErrorNotInitialized;
  241. }
  242. // Tear down the render window.
  243. m_window.reset();
  244. }
  245. void PauseEmulation() {
  246. std::scoped_lock lock(m_mutex);
  247. m_system.Pause();
  248. m_is_paused = true;
  249. }
  250. void UnPauseEmulation() {
  251. std::scoped_lock lock(m_mutex);
  252. m_system.Run();
  253. m_is_paused = false;
  254. }
  255. void HaltEmulation() {
  256. std::scoped_lock lock(m_mutex);
  257. m_is_running = false;
  258. m_cv.notify_one();
  259. }
  260. void RunEmulation() {
  261. {
  262. std::scoped_lock lock(m_mutex);
  263. m_is_running = true;
  264. }
  265. // Load the disk shader cache.
  266. if (Settings::values.use_disk_shader_cache.GetValue()) {
  267. LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
  268. m_system.Renderer().ReadRasterizer()->LoadDiskResources(
  269. m_system.GetApplicationProcessProgramID(), std::stop_token{},
  270. LoadDiskCacheProgress);
  271. LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
  272. }
  273. void(m_system.Run());
  274. if (m_system.DebuggerEnabled()) {
  275. m_system.InitializeDebugger();
  276. }
  277. while (true) {
  278. {
  279. std::unique_lock lock(m_mutex);
  280. if (m_cv.wait_for(lock, std::chrono::milliseconds(800),
  281. [&]() { return !m_is_running; })) {
  282. // Emulation halted.
  283. break;
  284. }
  285. }
  286. {
  287. // Refresh performance stats.
  288. std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex);
  289. m_perf_stats = m_system.GetAndResetPerfStats();
  290. }
  291. }
  292. }
  293. std::string GetRomTitle(const std::string& path) {
  294. return GetRomMetadata(path).title;
  295. }
  296. std::vector<u8> GetRomIcon(const std::string& path) {
  297. return GetRomMetadata(path).icon;
  298. }
  299. bool GetIsHomebrew(const std::string& path) {
  300. return GetRomMetadata(path).isHomebrew;
  301. }
  302. void ResetRomMetadata() {
  303. m_rom_metadata_cache.clear();
  304. }
  305. bool IsHandheldOnly() {
  306. const auto npad_style_set = m_system.HIDCore().GetSupportedStyleTag();
  307. if (npad_style_set.fullkey == 1) {
  308. return false;
  309. }
  310. if (npad_style_set.handheld == 0) {
  311. return false;
  312. }
  313. return !Settings::values.use_docked_mode.GetValue();
  314. }
  315. void SetDeviceType(int index, int type) {
  316. auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
  317. controller->SetNpadStyleIndex(static_cast<Core::HID::NpadStyleIndex>(type));
  318. }
  319. void OnGamepadConnectEvent(int index) {
  320. auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
  321. // Ensure that player1 is configured correctly and handheld disconnected
  322. if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) {
  323. auto handheld =
  324. m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
  325. if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) {
  326. handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
  327. controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
  328. handheld->Disconnect();
  329. }
  330. }
  331. // Ensure that handheld is configured correctly and player 1 disconnected
  332. if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) {
  333. auto player1 = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
  334. if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) {
  335. player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
  336. controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
  337. player1->Disconnect();
  338. }
  339. }
  340. if (!controller->IsConnected()) {
  341. controller->Connect();
  342. }
  343. }
  344. void OnGamepadDisconnectEvent(int index) {
  345. auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
  346. controller->Disconnect();
  347. }
  348. SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard() {
  349. return m_software_keyboard;
  350. }
  351. private:
  352. struct RomMetadata {
  353. std::string title;
  354. std::vector<u8> icon;
  355. bool isHomebrew;
  356. };
  357. RomMetadata GetRomMetadata(const std::string& path) {
  358. if (auto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) {
  359. return search->second;
  360. }
  361. return CacheRomMetadata(path);
  362. }
  363. RomMetadata CacheRomMetadata(const std::string& path) {
  364. const auto file = Core::GetGameFileFromPath(m_vfs, path);
  365. auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
  366. RomMetadata entry;
  367. loader->ReadTitle(entry.title);
  368. loader->ReadIcon(entry.icon);
  369. if (loader->GetFileType() == Loader::FileType::NRO) {
  370. auto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get());
  371. entry.isHomebrew = loader_nro->IsHomebrew();
  372. } else {
  373. entry.isHomebrew = false;
  374. }
  375. m_rom_metadata_cache[path] = entry;
  376. return entry;
  377. }
  378. private:
  379. static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max) {
  380. JNIEnv* env = IDCache::GetEnvForThread();
  381. env->CallStaticVoidMethod(IDCache::GetDiskCacheProgressClass(),
  382. IDCache::GetDiskCacheLoadProgress(), static_cast<jint>(stage),
  383. static_cast<jint>(progress), static_cast<jint>(max));
  384. }
  385. private:
  386. static EmulationSession s_instance;
  387. // Frontend management
  388. std::unordered_map<std::string, RomMetadata> m_rom_metadata_cache;
  389. // Window management
  390. std::unique_ptr<EmuWindow_Android> m_window;
  391. ANativeWindow* m_native_window{};
  392. // Core emulation
  393. Core::System m_system;
  394. InputCommon::InputSubsystem m_input_subsystem;
  395. Common::DetachedTasks m_detached_tasks;
  396. Core::PerfStatsResults m_perf_stats{};
  397. std::shared_ptr<FileSys::VfsFilesystem> m_vfs;
  398. Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
  399. bool m_is_running{};
  400. bool m_is_paused{};
  401. SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
  402. std::unique_ptr<Service::Account::ProfileManager> m_profile_manager;
  403. // GPU driver parameters
  404. std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
  405. // Synchronization
  406. std::condition_variable_any m_cv;
  407. mutable std::mutex m_perf_stats_mutex;
  408. mutable std::mutex m_mutex;
  409. };
  410. /*static*/ EmulationSession EmulationSession::s_instance;
  411. } // Anonymous namespace
  412. static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
  413. Common::Log::Initialize();
  414. Common::Log::SetColorConsoleBackendEnabled(true);
  415. Common::Log::Start();
  416. MicroProfileOnThreadCreate("EmuThread");
  417. SCOPE_EXIT({ MicroProfileShutdown(); });
  418. LOG_INFO(Frontend, "starting");
  419. if (filepath.empty()) {
  420. LOG_CRITICAL(Frontend, "failed to load: filepath empty!");
  421. return Core::SystemResultStatus::ErrorLoader;
  422. }
  423. SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); });
  424. const auto result = EmulationSession::GetInstance().InitializeEmulation(filepath);
  425. if (result != Core::SystemResultStatus::Success) {
  426. return result;
  427. }
  428. EmulationSession::GetInstance().RunEmulation();
  429. return Core::SystemResultStatus::Success;
  430. }
  431. extern "C" {
  432. void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env,
  433. [[maybe_unused]] jclass clazz,
  434. jobject surf) {
  435. EmulationSession::GetInstance().SetNativeWindow(ANativeWindow_fromSurface(env, surf));
  436. EmulationSession::GetInstance().SurfaceChanged();
  437. }
  438. void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env,
  439. [[maybe_unused]] jclass clazz) {
  440. ANativeWindow_release(EmulationSession::GetInstance().NativeWindow());
  441. EmulationSession::GetInstance().SetNativeWindow(nullptr);
  442. EmulationSession::GetInstance().SurfaceChanged();
  443. }
  444. void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env,
  445. [[maybe_unused]] jclass clazz,
  446. jstring j_directory) {
  447. Common::FS::SetAppDirectory(GetJString(env, j_directory));
  448. }
  449. int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env,
  450. [[maybe_unused]] jclass clazz,
  451. jstring j_file) {
  452. return EmulationSession::GetInstance().InstallFileToNand(GetJString(env, j_file));
  453. }
  454. void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(
  455. JNIEnv* env, [[maybe_unused]] jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir,
  456. jstring custom_driver_name, jstring file_redirect_dir) {
  457. EmulationSession::GetInstance().InitializeGpuDriver(
  458. GetJString(env, hook_lib_dir), GetJString(env, custom_driver_dir),
  459. GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir));
  460. }
  461. [[maybe_unused]] static bool CheckKgslPresent() {
  462. constexpr auto KgslPath{"/dev/kgsl-3d0"};
  463. return access(KgslPath, F_OK) == 0;
  464. }
  465. [[maybe_unused]] bool SupportsCustomDriver() {
  466. return android_get_device_api_level() >= 28 && CheckKgslPresent();
  467. }
  468. jboolean JNICALL Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_supportsCustomDriverLoading(
  469. [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject instance) {
  470. #ifdef ARCHITECTURE_arm64
  471. // If the KGSL device exists custom drivers can be loaded using adrenotools
  472. return SupportsCustomDriver();
  473. #else
  474. return false;
  475. #endif
  476. }
  477. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env,
  478. [[maybe_unused]] jclass clazz) {
  479. Core::Crypto::KeyManager::Instance().ReloadKeys();
  480. return static_cast<jboolean>(Core::Crypto::KeyManager::Instance().AreKeysLoaded());
  481. }
  482. void Java_org_yuzu_yuzu_1emu_NativeLibrary_unPauseEmulation([[maybe_unused]] JNIEnv* env,
  483. [[maybe_unused]] jclass clazz) {
  484. EmulationSession::GetInstance().UnPauseEmulation();
  485. }
  486. void Java_org_yuzu_yuzu_1emu_NativeLibrary_pauseEmulation([[maybe_unused]] JNIEnv* env,
  487. [[maybe_unused]] jclass clazz) {
  488. EmulationSession::GetInstance().PauseEmulation();
  489. }
  490. void Java_org_yuzu_yuzu_1emu_NativeLibrary_stopEmulation([[maybe_unused]] JNIEnv* env,
  491. [[maybe_unused]] jclass clazz) {
  492. EmulationSession::GetInstance().HaltEmulation();
  493. }
  494. void Java_org_yuzu_yuzu_1emu_NativeLibrary_resetRomMetadata([[maybe_unused]] JNIEnv* env,
  495. [[maybe_unused]] jclass clazz) {
  496. EmulationSession::GetInstance().ResetRomMetadata();
  497. }
  498. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isRunning([[maybe_unused]] JNIEnv* env,
  499. [[maybe_unused]] jclass clazz) {
  500. return static_cast<jboolean>(EmulationSession::GetInstance().IsRunning());
  501. }
  502. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isPaused([[maybe_unused]] JNIEnv* env,
  503. [[maybe_unused]] jclass clazz) {
  504. return static_cast<jboolean>(EmulationSession::GetInstance().IsPaused());
  505. }
  506. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHandheldOnly([[maybe_unused]] JNIEnv* env,
  507. [[maybe_unused]] jclass clazz) {
  508. return EmulationSession::GetInstance().IsHandheldOnly();
  509. }
  510. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_setDeviceType([[maybe_unused]] JNIEnv* env,
  511. [[maybe_unused]] jclass clazz,
  512. jint j_device, jint j_type) {
  513. if (EmulationSession::GetInstance().IsRunning()) {
  514. EmulationSession::GetInstance().SetDeviceType(j_device, j_type);
  515. }
  516. return static_cast<jboolean>(true);
  517. }
  518. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadConnectEvent([[maybe_unused]] JNIEnv* env,
  519. [[maybe_unused]] jclass clazz,
  520. jint j_device) {
  521. if (EmulationSession::GetInstance().IsRunning()) {
  522. EmulationSession::GetInstance().OnGamepadConnectEvent(j_device);
  523. }
  524. return static_cast<jboolean>(true);
  525. }
  526. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent(
  527. [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device) {
  528. if (EmulationSession::GetInstance().IsRunning()) {
  529. EmulationSession::GetInstance().OnGamepadDisconnectEvent(j_device);
  530. }
  531. return static_cast<jboolean>(true);
  532. }
  533. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent([[maybe_unused]] JNIEnv* env,
  534. [[maybe_unused]] jclass clazz,
  535. [[maybe_unused]] jint j_device,
  536. jint j_button, jint action) {
  537. if (EmulationSession::GetInstance().IsRunning()) {
  538. // Ensure gamepad is connected
  539. EmulationSession::GetInstance().OnGamepadConnectEvent(j_device);
  540. EmulationSession::GetInstance().Window().OnGamepadButtonEvent(j_device, j_button,
  541. action != 0);
  542. }
  543. return static_cast<jboolean>(true);
  544. }
  545. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadJoystickEvent([[maybe_unused]] JNIEnv* env,
  546. [[maybe_unused]] jclass clazz,
  547. jint j_device, jint stick_id,
  548. jfloat x, jfloat y) {
  549. if (EmulationSession::GetInstance().IsRunning()) {
  550. EmulationSession::GetInstance().Window().OnGamepadJoystickEvent(j_device, stick_id, x, y);
  551. }
  552. return static_cast<jboolean>(true);
  553. }
  554. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent(
  555. [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device,
  556. jlong delta_timestamp, jfloat gyro_x, jfloat gyro_y, jfloat gyro_z, jfloat accel_x,
  557. jfloat accel_y, jfloat accel_z) {
  558. if (EmulationSession::GetInstance().IsRunning()) {
  559. EmulationSession::GetInstance().Window().OnGamepadMotionEvent(
  560. j_device, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z);
  561. }
  562. return static_cast<jboolean>(true);
  563. }
  564. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag([[maybe_unused]] JNIEnv* env,
  565. [[maybe_unused]] jclass clazz,
  566. jbyteArray j_data) {
  567. jboolean isCopy{false};
  568. std::span<u8> data(reinterpret_cast<u8*>(env->GetByteArrayElements(j_data, &isCopy)),
  569. static_cast<size_t>(env->GetArrayLength(j_data)));
  570. if (EmulationSession::GetInstance().IsRunning()) {
  571. EmulationSession::GetInstance().Window().OnReadNfcTag(data);
  572. }
  573. return static_cast<jboolean>(true);
  574. }
  575. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onRemoveNfcTag([[maybe_unused]] JNIEnv* env,
  576. [[maybe_unused]] jclass clazz) {
  577. if (EmulationSession::GetInstance().IsRunning()) {
  578. EmulationSession::GetInstance().Window().OnRemoveNfcTag();
  579. }
  580. return static_cast<jboolean>(true);
  581. }
  582. void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchPressed([[maybe_unused]] JNIEnv* env,
  583. [[maybe_unused]] jclass clazz, jint id,
  584. jfloat x, jfloat y) {
  585. if (EmulationSession::GetInstance().IsRunning()) {
  586. EmulationSession::GetInstance().Window().OnTouchPressed(id, x, y);
  587. }
  588. }
  589. void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved([[maybe_unused]] JNIEnv* env,
  590. [[maybe_unused]] jclass clazz, jint id,
  591. jfloat x, jfloat y) {
  592. if (EmulationSession::GetInstance().IsRunning()) {
  593. EmulationSession::GetInstance().Window().OnTouchMoved(id, x, y);
  594. }
  595. }
  596. void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased([[maybe_unused]] JNIEnv* env,
  597. [[maybe_unused]] jclass clazz, jint id) {
  598. if (EmulationSession::GetInstance().IsRunning()) {
  599. EmulationSession::GetInstance().Window().OnTouchReleased(id);
  600. }
  601. }
  602. jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon([[maybe_unused]] JNIEnv* env,
  603. [[maybe_unused]] jclass clazz,
  604. [[maybe_unused]] jstring j_filename) {
  605. auto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename));
  606. jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size()));
  607. env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon),
  608. reinterpret_cast<jbyte*>(icon_data.data()));
  609. return icon;
  610. }
  611. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getTitle([[maybe_unused]] JNIEnv* env,
  612. [[maybe_unused]] jclass clazz,
  613. [[maybe_unused]] jstring j_filename) {
  614. auto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename));
  615. return env->NewStringUTF(title.c_str());
  616. }
  617. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDescription([[maybe_unused]] JNIEnv* env,
  618. [[maybe_unused]] jclass clazz,
  619. jstring j_filename) {
  620. return j_filename;
  621. }
  622. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGameId([[maybe_unused]] JNIEnv* env,
  623. [[maybe_unused]] jclass clazz,
  624. jstring j_filename) {
  625. return j_filename;
  626. }
  627. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getRegions([[maybe_unused]] JNIEnv* env,
  628. [[maybe_unused]] jclass clazz,
  629. [[maybe_unused]] jstring j_filename) {
  630. return env->NewStringUTF("");
  631. }
  632. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany([[maybe_unused]] JNIEnv* env,
  633. [[maybe_unused]] jclass clazz,
  634. [[maybe_unused]] jstring j_filename) {
  635. return env->NewStringUTF("");
  636. }
  637. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew([[maybe_unused]] JNIEnv* env,
  638. [[maybe_unused]] jclass clazz,
  639. [[maybe_unused]] jstring j_filename) {
  640. return EmulationSession::GetInstance().GetIsHomebrew(GetJString(env, j_filename));
  641. }
  642. void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation
  643. [[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) {
  644. // Create the default config.ini.
  645. Config{};
  646. // Initialize the emulated system.
  647. EmulationSession::GetInstance().System().Initialize();
  648. }
  649. jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore([[maybe_unused]] JNIEnv* env,
  650. [[maybe_unused]] jclass clazz) {
  651. return {};
  652. }
  653. void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z(
  654. [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, [[maybe_unused]] jstring j_file,
  655. [[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {}
  656. void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings([[maybe_unused]] JNIEnv* env,
  657. [[maybe_unused]] jclass clazz) {
  658. Config{};
  659. }
  660. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getUserSetting([[maybe_unused]] JNIEnv* env,
  661. [[maybe_unused]] jclass clazz,
  662. jstring j_game_id, jstring j_section,
  663. jstring j_key) {
  664. std::string_view game_id = env->GetStringUTFChars(j_game_id, 0);
  665. std::string_view section = env->GetStringUTFChars(j_section, 0);
  666. std::string_view key = env->GetStringUTFChars(j_key, 0);
  667. env->ReleaseStringUTFChars(j_game_id, game_id.data());
  668. env->ReleaseStringUTFChars(j_section, section.data());
  669. env->ReleaseStringUTFChars(j_key, key.data());
  670. return env->NewStringUTF("");
  671. }
  672. void Java_org_yuzu_yuzu_1emu_NativeLibrary_setUserSetting([[maybe_unused]] JNIEnv* env,
  673. [[maybe_unused]] jclass clazz,
  674. jstring j_game_id, jstring j_section,
  675. jstring j_key, jstring j_value) {
  676. std::string_view game_id = env->GetStringUTFChars(j_game_id, 0);
  677. std::string_view section = env->GetStringUTFChars(j_section, 0);
  678. std::string_view key = env->GetStringUTFChars(j_key, 0);
  679. std::string_view value = env->GetStringUTFChars(j_value, 0);
  680. env->ReleaseStringUTFChars(j_game_id, game_id.data());
  681. env->ReleaseStringUTFChars(j_section, section.data());
  682. env->ReleaseStringUTFChars(j_key, key.data());
  683. env->ReleaseStringUTFChars(j_value, value.data());
  684. }
  685. void Java_org_yuzu_yuzu_1emu_NativeLibrary_initGameIni([[maybe_unused]] JNIEnv* env,
  686. [[maybe_unused]] jclass clazz,
  687. jstring j_game_id) {
  688. std::string_view game_id = env->GetStringUTFChars(j_game_id, 0);
  689. env->ReleaseStringUTFChars(j_game_id, game_id.data());
  690. }
  691. jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats([[maybe_unused]] JNIEnv* env,
  692. [[maybe_unused]] jclass clazz) {
  693. jdoubleArray j_stats = env->NewDoubleArray(4);
  694. if (EmulationSession::GetInstance().IsRunning()) {
  695. const auto results = EmulationSession::GetInstance().PerfStats();
  696. // Converting the structure into an array makes it easier to pass it to the frontend
  697. double stats[4] = {results.system_fps, results.average_game_fps, results.frametime,
  698. results.emulation_speed};
  699. env->SetDoubleArrayRegion(j_stats, 0, 4, stats);
  700. }
  701. return j_stats;
  702. }
  703. void Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_setSysDirectory(
  704. [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jstring j_path) {}
  705. void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2([[maybe_unused]] JNIEnv* env,
  706. [[maybe_unused]] jclass clazz,
  707. jstring j_path) {
  708. const std::string path = GetJString(env, j_path);
  709. const Core::SystemResultStatus result{RunEmulation(path)};
  710. if (result != Core::SystemResultStatus::Success) {
  711. env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),
  712. IDCache::GetExitEmulationActivity(), static_cast<int>(result));
  713. }
  714. }
  715. void Java_org_yuzu_yuzu_1emu_NativeLibrary_logDeviceInfo([[maybe_unused]] JNIEnv* env,
  716. [[maybe_unused]] jclass clazz) {
  717. LOG_INFO(Frontend, "yuzu Version: {}-{}", Common::g_scm_branch, Common::g_scm_desc);
  718. LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level());
  719. }
  720. void Java_org_yuzu_yuzu_1emu_NativeLibrary_submitInlineKeyboardText(JNIEnv* env, jclass clazz,
  721. jstring j_text) {
  722. const std::u16string input = Common::UTF8ToUTF16(GetJString(env, j_text));
  723. EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardText(input);
  724. }
  725. void Java_org_yuzu_yuzu_1emu_NativeLibrary_submitInlineKeyboardInput(JNIEnv* env, jclass clazz,
  726. jint j_key_code) {
  727. EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardInput(j_key_code);
  728. }
  729. } // extern "C"