native.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  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. const Core::PerfStatsResults& PerfStats() const {
  175. std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex);
  176. return m_perf_stats;
  177. }
  178. void SurfaceChanged() {
  179. if (!IsRunning()) {
  180. return;
  181. }
  182. m_window->OnSurfaceChanged(m_native_window);
  183. m_system.Renderer().NotifySurfaceChanged();
  184. }
  185. Core::SystemResultStatus InitializeEmulation(const std::string& filepath) {
  186. std::scoped_lock lock(m_mutex);
  187. // Loads the configuration.
  188. Config{};
  189. // Create the render window.
  190. m_window = std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window,
  191. m_vulkan_library);
  192. m_system.SetFilesystem(m_vfs);
  193. // Initialize system.
  194. auto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>();
  195. m_software_keyboard = android_keyboard.get();
  196. m_system.SetShuttingDown(false);
  197. m_system.ApplySettings();
  198. m_system.HIDCore().ReloadInputDevices();
  199. m_system.SetAppletFrontendSet({
  200. nullptr, // Amiibo Settings
  201. nullptr, // Controller Selector
  202. nullptr, // Error Display
  203. nullptr, // Mii Editor
  204. nullptr, // Parental Controls
  205. nullptr, // Photo Viewer
  206. nullptr, // Profile Selector
  207. std::move(android_keyboard), // Software Keyboard
  208. nullptr, // Web Browser
  209. });
  210. m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
  211. m_system.GetFileSystemController().CreateFactories(*m_vfs);
  212. // Initialize account manager
  213. m_profile_manager = std::make_unique<Service::Account::ProfileManager>();
  214. // Load the ROM.
  215. m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath);
  216. if (m_load_result != Core::SystemResultStatus::Success) {
  217. return m_load_result;
  218. }
  219. // Complete initialization.
  220. m_system.GPU().Start();
  221. m_system.GetCpuManager().OnGpuReady();
  222. m_system.RegisterExitCallback([&] { HaltEmulation(); });
  223. return Core::SystemResultStatus::Success;
  224. }
  225. void ShutdownEmulation() {
  226. std::scoped_lock lock(m_mutex);
  227. m_is_running = false;
  228. // Unload user input.
  229. m_system.HIDCore().UnloadInputDevices();
  230. // Shutdown the main emulated process
  231. if (m_load_result == Core::SystemResultStatus::Success) {
  232. m_system.DetachDebugger();
  233. m_system.ShutdownMainProcess();
  234. m_detached_tasks.WaitForAllTasks();
  235. m_load_result = Core::SystemResultStatus::ErrorNotInitialized;
  236. }
  237. // Tear down the render window.
  238. m_window.reset();
  239. }
  240. void PauseEmulation() {
  241. std::scoped_lock lock(m_mutex);
  242. m_system.Pause();
  243. }
  244. void UnPauseEmulation() {
  245. std::scoped_lock lock(m_mutex);
  246. m_system.Run();
  247. }
  248. void HaltEmulation() {
  249. std::scoped_lock lock(m_mutex);
  250. m_is_running = false;
  251. m_cv.notify_one();
  252. }
  253. void RunEmulation() {
  254. {
  255. std::scoped_lock lock(m_mutex);
  256. m_is_running = true;
  257. }
  258. // Load the disk shader cache.
  259. if (Settings::values.use_disk_shader_cache.GetValue()) {
  260. LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
  261. m_system.Renderer().ReadRasterizer()->LoadDiskResources(
  262. m_system.GetApplicationProcessProgramID(), std::stop_token{},
  263. LoadDiskCacheProgress);
  264. LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
  265. }
  266. void(m_system.Run());
  267. if (m_system.DebuggerEnabled()) {
  268. m_system.InitializeDebugger();
  269. }
  270. while (true) {
  271. {
  272. std::unique_lock lock(m_mutex);
  273. if (m_cv.wait_for(lock, std::chrono::milliseconds(800),
  274. [&]() { return !m_is_running; })) {
  275. // Emulation halted.
  276. break;
  277. }
  278. }
  279. {
  280. // Refresh performance stats.
  281. std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex);
  282. m_perf_stats = m_system.GetAndResetPerfStats();
  283. }
  284. }
  285. }
  286. std::string GetRomTitle(const std::string& path) {
  287. return GetRomMetadata(path).title;
  288. }
  289. std::vector<u8> GetRomIcon(const std::string& path) {
  290. return GetRomMetadata(path).icon;
  291. }
  292. bool GetIsHomebrew(const std::string& path) {
  293. return GetRomMetadata(path).isHomebrew;
  294. }
  295. void ResetRomMetadata() {
  296. m_rom_metadata_cache.clear();
  297. }
  298. bool IsHandheldOnly() {
  299. const auto npad_style_set = m_system.HIDCore().GetSupportedStyleTag();
  300. if (npad_style_set.fullkey == 1) {
  301. return false;
  302. }
  303. if (npad_style_set.handheld == 0) {
  304. return false;
  305. }
  306. return !Settings::values.use_docked_mode.GetValue();
  307. }
  308. void SetDeviceType(int index, int type) {
  309. auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
  310. controller->SetNpadStyleIndex(static_cast<Core::HID::NpadStyleIndex>(type));
  311. }
  312. void OnGamepadConnectEvent(int index) {
  313. auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
  314. // Ensure that player1 is configured correctly and handheld disconnected
  315. if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) {
  316. auto handheld =
  317. m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
  318. if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) {
  319. handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
  320. controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
  321. handheld->Disconnect();
  322. }
  323. }
  324. // Ensure that handheld is configured correctly and player 1 disconnected
  325. if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) {
  326. auto player1 = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
  327. if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) {
  328. player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
  329. controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
  330. player1->Disconnect();
  331. }
  332. }
  333. if (!controller->IsConnected()) {
  334. controller->Connect();
  335. }
  336. }
  337. void OnGamepadDisconnectEvent(int index) {
  338. auto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
  339. controller->Disconnect();
  340. }
  341. SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard() {
  342. return m_software_keyboard;
  343. }
  344. private:
  345. struct RomMetadata {
  346. std::string title;
  347. std::vector<u8> icon;
  348. bool isHomebrew;
  349. };
  350. RomMetadata GetRomMetadata(const std::string& path) {
  351. if (auto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) {
  352. return search->second;
  353. }
  354. return CacheRomMetadata(path);
  355. }
  356. RomMetadata CacheRomMetadata(const std::string& path) {
  357. const auto file = Core::GetGameFileFromPath(m_vfs, path);
  358. auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
  359. RomMetadata entry;
  360. loader->ReadTitle(entry.title);
  361. loader->ReadIcon(entry.icon);
  362. if (loader->GetFileType() == Loader::FileType::NRO) {
  363. auto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get());
  364. entry.isHomebrew = loader_nro->IsHomebrew();
  365. } else {
  366. entry.isHomebrew = false;
  367. }
  368. m_rom_metadata_cache[path] = entry;
  369. return entry;
  370. }
  371. private:
  372. static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max) {
  373. JNIEnv* env = IDCache::GetEnvForThread();
  374. env->CallStaticVoidMethod(IDCache::GetDiskCacheProgressClass(),
  375. IDCache::GetDiskCacheLoadProgress(), static_cast<jint>(stage),
  376. static_cast<jint>(progress), static_cast<jint>(max));
  377. }
  378. private:
  379. static EmulationSession s_instance;
  380. // Frontend management
  381. std::unordered_map<std::string, RomMetadata> m_rom_metadata_cache;
  382. // Window management
  383. std::unique_ptr<EmuWindow_Android> m_window;
  384. ANativeWindow* m_native_window{};
  385. // Core emulation
  386. Core::System m_system;
  387. InputCommon::InputSubsystem m_input_subsystem;
  388. Common::DetachedTasks m_detached_tasks;
  389. Core::PerfStatsResults m_perf_stats{};
  390. std::shared_ptr<FileSys::VfsFilesystem> m_vfs;
  391. Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
  392. bool m_is_running{};
  393. SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
  394. std::unique_ptr<Service::Account::ProfileManager> m_profile_manager;
  395. // GPU driver parameters
  396. std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
  397. // Synchronization
  398. std::condition_variable_any m_cv;
  399. mutable std::mutex m_perf_stats_mutex;
  400. mutable std::mutex m_mutex;
  401. };
  402. /*static*/ EmulationSession EmulationSession::s_instance;
  403. } // Anonymous namespace
  404. static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
  405. Common::Log::Initialize();
  406. Common::Log::SetColorConsoleBackendEnabled(true);
  407. Common::Log::Start();
  408. MicroProfileOnThreadCreate("EmuThread");
  409. SCOPE_EXIT({ MicroProfileShutdown(); });
  410. LOG_INFO(Frontend, "starting");
  411. if (filepath.empty()) {
  412. LOG_CRITICAL(Frontend, "failed to load: filepath empty!");
  413. return Core::SystemResultStatus::ErrorLoader;
  414. }
  415. SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); });
  416. const auto result = EmulationSession::GetInstance().InitializeEmulation(filepath);
  417. if (result != Core::SystemResultStatus::Success) {
  418. return result;
  419. }
  420. EmulationSession::GetInstance().RunEmulation();
  421. return Core::SystemResultStatus::Success;
  422. }
  423. extern "C" {
  424. void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env,
  425. [[maybe_unused]] jclass clazz,
  426. jobject surf) {
  427. EmulationSession::GetInstance().SetNativeWindow(ANativeWindow_fromSurface(env, surf));
  428. EmulationSession::GetInstance().SurfaceChanged();
  429. }
  430. void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env,
  431. [[maybe_unused]] jclass clazz) {
  432. ANativeWindow_release(EmulationSession::GetInstance().NativeWindow());
  433. EmulationSession::GetInstance().SetNativeWindow(nullptr);
  434. EmulationSession::GetInstance().SurfaceChanged();
  435. }
  436. void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env,
  437. [[maybe_unused]] jclass clazz,
  438. jstring j_directory) {
  439. Common::FS::SetAppDirectory(GetJString(env, j_directory));
  440. }
  441. int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env,
  442. [[maybe_unused]] jclass clazz,
  443. jstring j_file) {
  444. return EmulationSession::GetInstance().InstallFileToNand(GetJString(env, j_file));
  445. }
  446. void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(
  447. JNIEnv* env, [[maybe_unused]] jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir,
  448. jstring custom_driver_name, jstring file_redirect_dir) {
  449. EmulationSession::GetInstance().InitializeGpuDriver(
  450. GetJString(env, hook_lib_dir), GetJString(env, custom_driver_dir),
  451. GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir));
  452. }
  453. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env,
  454. [[maybe_unused]] jclass clazz) {
  455. Core::Crypto::KeyManager::Instance().ReloadKeys();
  456. return static_cast<jboolean>(Core::Crypto::KeyManager::Instance().AreKeysLoaded());
  457. }
  458. void Java_org_yuzu_yuzu_1emu_NativeLibrary_unPauseEmulation([[maybe_unused]] JNIEnv* env,
  459. [[maybe_unused]] jclass clazz) {
  460. EmulationSession::GetInstance().UnPauseEmulation();
  461. }
  462. void Java_org_yuzu_yuzu_1emu_NativeLibrary_pauseEmulation([[maybe_unused]] JNIEnv* env,
  463. [[maybe_unused]] jclass clazz) {
  464. EmulationSession::GetInstance().PauseEmulation();
  465. }
  466. void Java_org_yuzu_yuzu_1emu_NativeLibrary_stopEmulation([[maybe_unused]] JNIEnv* env,
  467. [[maybe_unused]] jclass clazz) {
  468. EmulationSession::GetInstance().HaltEmulation();
  469. }
  470. void Java_org_yuzu_yuzu_1emu_NativeLibrary_resetRomMetadata([[maybe_unused]] JNIEnv* env,
  471. [[maybe_unused]] jclass clazz) {
  472. EmulationSession::GetInstance().ResetRomMetadata();
  473. }
  474. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isRunning([[maybe_unused]] JNIEnv* env,
  475. [[maybe_unused]] jclass clazz) {
  476. return static_cast<jboolean>(EmulationSession::GetInstance().IsRunning());
  477. }
  478. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHandheldOnly([[maybe_unused]] JNIEnv* env,
  479. [[maybe_unused]] jclass clazz) {
  480. return EmulationSession::GetInstance().IsHandheldOnly();
  481. }
  482. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_setDeviceType([[maybe_unused]] JNIEnv* env,
  483. [[maybe_unused]] jclass clazz,
  484. jint j_device, jint j_type) {
  485. if (EmulationSession::GetInstance().IsRunning()) {
  486. EmulationSession::GetInstance().SetDeviceType(j_device, j_type);
  487. }
  488. return static_cast<jboolean>(true);
  489. }
  490. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadConnectEvent([[maybe_unused]] JNIEnv* env,
  491. [[maybe_unused]] jclass clazz,
  492. jint j_device) {
  493. if (EmulationSession::GetInstance().IsRunning()) {
  494. EmulationSession::GetInstance().OnGamepadConnectEvent(j_device);
  495. }
  496. return static_cast<jboolean>(true);
  497. }
  498. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent(
  499. [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device) {
  500. if (EmulationSession::GetInstance().IsRunning()) {
  501. EmulationSession::GetInstance().OnGamepadDisconnectEvent(j_device);
  502. }
  503. return static_cast<jboolean>(true);
  504. }
  505. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent([[maybe_unused]] JNIEnv* env,
  506. [[maybe_unused]] jclass clazz,
  507. [[maybe_unused]] jint j_device,
  508. jint j_button, jint action) {
  509. if (EmulationSession::GetInstance().IsRunning()) {
  510. // Ensure gamepad is connected
  511. EmulationSession::GetInstance().OnGamepadConnectEvent(j_device);
  512. EmulationSession::GetInstance().Window().OnGamepadButtonEvent(j_device, j_button,
  513. action != 0);
  514. }
  515. return static_cast<jboolean>(true);
  516. }
  517. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadJoystickEvent([[maybe_unused]] JNIEnv* env,
  518. [[maybe_unused]] jclass clazz,
  519. jint j_device, jint stick_id,
  520. jfloat x, jfloat y) {
  521. if (EmulationSession::GetInstance().IsRunning()) {
  522. EmulationSession::GetInstance().Window().OnGamepadJoystickEvent(j_device, stick_id, x, y);
  523. }
  524. return static_cast<jboolean>(true);
  525. }
  526. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent(
  527. [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jint j_device,
  528. jlong delta_timestamp, jfloat gyro_x, jfloat gyro_y, jfloat gyro_z, jfloat accel_x,
  529. jfloat accel_y, jfloat accel_z) {
  530. if (EmulationSession::GetInstance().IsRunning()) {
  531. EmulationSession::GetInstance().Window().OnGamepadMotionEvent(
  532. j_device, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z);
  533. }
  534. return static_cast<jboolean>(true);
  535. }
  536. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag([[maybe_unused]] JNIEnv* env,
  537. [[maybe_unused]] jclass clazz,
  538. jbyteArray j_data) {
  539. jboolean isCopy{false};
  540. std::span<u8> data(reinterpret_cast<u8*>(env->GetByteArrayElements(j_data, &isCopy)),
  541. static_cast<size_t>(env->GetArrayLength(j_data)));
  542. if (EmulationSession::GetInstance().IsRunning()) {
  543. EmulationSession::GetInstance().Window().OnReadNfcTag(data);
  544. }
  545. return static_cast<jboolean>(true);
  546. }
  547. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onRemoveNfcTag([[maybe_unused]] JNIEnv* env,
  548. [[maybe_unused]] jclass clazz) {
  549. if (EmulationSession::GetInstance().IsRunning()) {
  550. EmulationSession::GetInstance().Window().OnRemoveNfcTag();
  551. }
  552. return static_cast<jboolean>(true);
  553. }
  554. void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchPressed([[maybe_unused]] JNIEnv* env,
  555. [[maybe_unused]] jclass clazz, jint id,
  556. jfloat x, jfloat y) {
  557. if (EmulationSession::GetInstance().IsRunning()) {
  558. EmulationSession::GetInstance().Window().OnTouchPressed(id, x, y);
  559. }
  560. }
  561. void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved([[maybe_unused]] JNIEnv* env,
  562. [[maybe_unused]] jclass clazz, jint id,
  563. jfloat x, jfloat y) {
  564. if (EmulationSession::GetInstance().IsRunning()) {
  565. EmulationSession::GetInstance().Window().OnTouchMoved(id, x, y);
  566. }
  567. }
  568. void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased([[maybe_unused]] JNIEnv* env,
  569. [[maybe_unused]] jclass clazz, jint id) {
  570. if (EmulationSession::GetInstance().IsRunning()) {
  571. EmulationSession::GetInstance().Window().OnTouchReleased(id);
  572. }
  573. }
  574. jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon([[maybe_unused]] JNIEnv* env,
  575. [[maybe_unused]] jclass clazz,
  576. [[maybe_unused]] jstring j_filename) {
  577. auto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename));
  578. jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size()));
  579. env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon),
  580. reinterpret_cast<jbyte*>(icon_data.data()));
  581. return icon;
  582. }
  583. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getTitle([[maybe_unused]] JNIEnv* env,
  584. [[maybe_unused]] jclass clazz,
  585. [[maybe_unused]] jstring j_filename) {
  586. auto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename));
  587. return env->NewStringUTF(title.c_str());
  588. }
  589. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDescription([[maybe_unused]] JNIEnv* env,
  590. [[maybe_unused]] jclass clazz,
  591. jstring j_filename) {
  592. return j_filename;
  593. }
  594. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGameId([[maybe_unused]] JNIEnv* env,
  595. [[maybe_unused]] jclass clazz,
  596. jstring j_filename) {
  597. return j_filename;
  598. }
  599. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getRegions([[maybe_unused]] JNIEnv* env,
  600. [[maybe_unused]] jclass clazz,
  601. [[maybe_unused]] jstring j_filename) {
  602. return env->NewStringUTF("");
  603. }
  604. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany([[maybe_unused]] JNIEnv* env,
  605. [[maybe_unused]] jclass clazz,
  606. [[maybe_unused]] jstring j_filename) {
  607. return env->NewStringUTF("");
  608. }
  609. jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew([[maybe_unused]] JNIEnv* env,
  610. [[maybe_unused]] jclass clazz,
  611. [[maybe_unused]] jstring j_filename) {
  612. return EmulationSession::GetInstance().GetIsHomebrew(GetJString(env, j_filename));
  613. }
  614. void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation
  615. [[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) {
  616. // Create the default config.ini.
  617. Config{};
  618. // Initialize the emulated system.
  619. EmulationSession::GetInstance().System().Initialize();
  620. }
  621. jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore([[maybe_unused]] JNIEnv* env,
  622. [[maybe_unused]] jclass clazz) {
  623. return {};
  624. }
  625. void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z(
  626. [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, [[maybe_unused]] jstring j_file,
  627. [[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {}
  628. void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings([[maybe_unused]] JNIEnv* env,
  629. [[maybe_unused]] jclass clazz) {
  630. Config{};
  631. }
  632. jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getUserSetting([[maybe_unused]] JNIEnv* env,
  633. [[maybe_unused]] jclass clazz,
  634. jstring j_game_id, jstring j_section,
  635. jstring j_key) {
  636. std::string_view game_id = env->GetStringUTFChars(j_game_id, 0);
  637. std::string_view section = env->GetStringUTFChars(j_section, 0);
  638. std::string_view key = env->GetStringUTFChars(j_key, 0);
  639. env->ReleaseStringUTFChars(j_game_id, game_id.data());
  640. env->ReleaseStringUTFChars(j_section, section.data());
  641. env->ReleaseStringUTFChars(j_key, key.data());
  642. return env->NewStringUTF("");
  643. }
  644. void Java_org_yuzu_yuzu_1emu_NativeLibrary_setUserSetting([[maybe_unused]] JNIEnv* env,
  645. [[maybe_unused]] jclass clazz,
  646. jstring j_game_id, jstring j_section,
  647. jstring j_key, jstring j_value) {
  648. std::string_view game_id = env->GetStringUTFChars(j_game_id, 0);
  649. std::string_view section = env->GetStringUTFChars(j_section, 0);
  650. std::string_view key = env->GetStringUTFChars(j_key, 0);
  651. std::string_view value = env->GetStringUTFChars(j_value, 0);
  652. env->ReleaseStringUTFChars(j_game_id, game_id.data());
  653. env->ReleaseStringUTFChars(j_section, section.data());
  654. env->ReleaseStringUTFChars(j_key, key.data());
  655. env->ReleaseStringUTFChars(j_value, value.data());
  656. }
  657. void Java_org_yuzu_yuzu_1emu_NativeLibrary_initGameIni([[maybe_unused]] JNIEnv* env,
  658. [[maybe_unused]] jclass clazz,
  659. jstring j_game_id) {
  660. std::string_view game_id = env->GetStringUTFChars(j_game_id, 0);
  661. env->ReleaseStringUTFChars(j_game_id, game_id.data());
  662. }
  663. jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats([[maybe_unused]] JNIEnv* env,
  664. [[maybe_unused]] jclass clazz) {
  665. jdoubleArray j_stats = env->NewDoubleArray(4);
  666. if (EmulationSession::GetInstance().IsRunning()) {
  667. const auto results = EmulationSession::GetInstance().PerfStats();
  668. // Converting the structure into an array makes it easier to pass it to the frontend
  669. double stats[4] = {results.system_fps, results.average_game_fps, results.frametime,
  670. results.emulation_speed};
  671. env->SetDoubleArrayRegion(j_stats, 0, 4, stats);
  672. }
  673. return j_stats;
  674. }
  675. void Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_setSysDirectory(
  676. [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jstring j_path) {}
  677. void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2([[maybe_unused]] JNIEnv* env,
  678. [[maybe_unused]] jclass clazz,
  679. jstring j_path) {
  680. const std::string path = GetJString(env, j_path);
  681. const Core::SystemResultStatus result{RunEmulation(path)};
  682. if (result != Core::SystemResultStatus::Success) {
  683. env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),
  684. IDCache::GetExitEmulationActivity(), static_cast<int>(result));
  685. }
  686. }
  687. void Java_org_yuzu_yuzu_1emu_NativeLibrary_logDeviceInfo([[maybe_unused]] JNIEnv* env,
  688. [[maybe_unused]] jclass clazz) {
  689. LOG_INFO(Frontend, "yuzu Version: {}-{}", Common::g_scm_branch, Common::g_scm_desc);
  690. LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level());
  691. }
  692. void Java_org_yuzu_yuzu_1emu_NativeLibrary_submitInlineKeyboardText(JNIEnv* env, jclass clazz,
  693. jstring j_text) {
  694. const std::u16string input = Common::UTF8ToUTF16(GetJString(env, j_text));
  695. EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardText(input);
  696. }
  697. void Java_org_yuzu_yuzu_1emu_NativeLibrary_submitInlineKeyboardInput(JNIEnv* env, jclass clazz,
  698. jint j_key_code) {
  699. EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardInput(j_key_code);
  700. }
  701. } // extern "C"