yuzu/src/android/app/src/main/jni/native.cpp

902 lines
34 KiB
C++
Raw Normal View History

2023-05-31 10:37:04 +04:00
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <codecvt>
#include <locale>
#include <string>
#include <string_view>
#include <dlfcn.h>
#ifdef ARCHITECTURE_arm64
#include <adrenotools/driver.h>
#endif
#include <android/api-level.h>
#include <android/native_window_jni.h>
2023-09-27 22:05:05 +04:00
#include <common/fs/fs.h>
#include <core/file_sys/savedata_factory.h>
2023-06-10 12:26:16 +04:00
#include <core/loader/nro.h>
2023-06-23 19:15:59 +04:00
#include <jni.h>
2023-05-31 10:37:04 +04:00
#include "common/detached_tasks.h"
#include "common/dynamic_library.h"
#include "common/fs/path_util.h"
#include "common/logging/backend.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/scm_rev.h"
#include "common/scope_exit.h"
#include "common/settings.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/cpu_manager.h"
#include "core/crypto/key_manager.h"
2023-06-13 08:23:21 +04:00
#include "core/file_sys/card_image.h"
2023-08-26 01:54:37 +04:00
#include "core/file_sys/content_archive.h"
2023-05-31 10:37:04 +04:00
#include "core/file_sys/registered_cache.h"
2023-06-13 08:23:21 +04:00
#include "core/file_sys/submission_package.h"
#include "core/file_sys/vfs.h"
2023-05-31 10:37:04 +04:00
#include "core/file_sys/vfs_real.h"
#include "core/frontend/applets/cabinet.h"
#include "core/frontend/applets/controller.h"
#include "core/frontend/applets/error.h"
#include "core/frontend/applets/general_frontend.h"
#include "core/frontend/applets/mii_edit.h"
#include "core/frontend/applets/profile_select.h"
#include "core/frontend/applets/software_keyboard.h"
#include "core/frontend/applets/web_browser.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
#include "core/perf_stats.h"
#include "jni/android_common/android_common.h"
#include "jni/applets/software_keyboard.h"
#include "jni/config.h"
#include "jni/emu_window/emu_window.h"
#include "jni/id_cache.h"
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_base.h"
2023-06-27 00:11:43 +04:00
#define jconst [[maybe_unused]] const auto
#define jauto [[maybe_unused]] auto
2023-05-31 10:37:04 +04:00
namespace {
class EmulationSession final {
public:
EmulationSession() {
m_vfs = std::make_shared<FileSys::RealVfsFilesystem>();
}
~EmulationSession() = default;
static EmulationSession& GetInstance() {
return s_instance;
}
const Core::System& System() const {
return m_system;
}
Core::System& System() {
return m_system;
}
const EmuWindow_Android& Window() const {
return *m_window;
}
EmuWindow_Android& Window() {
return *m_window;
}
ANativeWindow* NativeWindow() const {
return m_native_window;
}
2023-06-02 12:28:14 +04:00
void SetNativeWindow(ANativeWindow* native_window) {
m_native_window = native_window;
}
2023-09-27 22:05:05 +04:00
int InstallFileToNand(std::string filename, std::string file_extension) {
2023-06-27 00:11:43 +04:00
jconst copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest,
std::size_t block_size) {
2023-06-13 08:23:21 +04:00
if (src == nullptr || dest == nullptr) {
return false;
}
if (!dest->Resize(src->GetSize())) {
return false;
}
using namespace Common::Literals;
2023-06-27 00:11:43 +04:00
[[maybe_unused]] std::vector<u8> buffer(1_MiB);
2023-06-13 08:23:21 +04:00
for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
2023-06-27 00:11:43 +04:00
jconst read = src->Read(buffer.data(), buffer.size(), i);
2023-06-13 08:23:21 +04:00
dest->Write(buffer.data(), read, i);
}
return true;
};
enum InstallResult {
Success = 0,
SuccessFileOverwritten = 1,
InstallError = 2,
ErrorBaseGame = 3,
ErrorFilenameExtension = 4,
};
m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
m_system.GetFileSystemController().CreateFactories(*m_vfs);
2023-06-27 00:11:43 +04:00
[[maybe_unused]] std::shared_ptr<FileSys::NSP> nsp;
2023-09-27 22:05:05 +04:00
if (file_extension == "nsp") {
2023-06-13 08:23:21 +04:00
nsp = std::make_shared<FileSys::NSP>(m_vfs->OpenFile(filename, FileSys::Mode::Read));
if (nsp->IsExtractedType()) {
return InstallError;
}
} else {
return ErrorFilenameExtension;
}
if (!nsp) {
return InstallError;
}
if (nsp->GetStatus() != Loader::ResultStatus::Success) {
return InstallError;
}
2023-06-27 00:11:43 +04:00
jconst res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry(
2023-06-13 08:23:21 +04:00
*nsp, true, copy_func);
switch (res) {
case FileSys::InstallResult::Success:
return Success;
case FileSys::InstallResult::OverwriteExisting:
return SuccessFileOverwritten;
case FileSys::InstallResult::ErrorBaseInstall:
return ErrorBaseGame;
default:
return InstallError;
}
}
2023-05-31 10:37:04 +04:00
void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir,
const std::string& custom_driver_name,
const std::string& file_redirect_dir) {
#ifdef ARCHITECTURE_arm64
void* handle{};
const char* file_redirect_dir_{};
int featureFlags{};
// Enable driver file redirection when renderer debugging is enabled.
if (Settings::values.renderer_debug && file_redirect_dir.size()) {
featureFlags |= ADRENOTOOLS_DRIVER_FILE_REDIRECT;
file_redirect_dir_ = file_redirect_dir.c_str();
}
// Try to load a custom driver.
if (custom_driver_name.size()) {
handle = adrenotools_open_libvulkan(
RTLD_NOW, featureFlags | ADRENOTOOLS_DRIVER_CUSTOM, nullptr, hook_lib_dir.c_str(),
custom_driver_dir.c_str(), custom_driver_name.c_str(), file_redirect_dir_, nullptr);
}
// Try to load the system driver.
if (!handle) {
handle =
adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(),
nullptr, nullptr, file_redirect_dir_, nullptr);
}
m_vulkan_library = std::make_shared<Common::DynamicLibrary>(handle);
#endif
}
bool IsRunning() const {
return m_is_running;
}
2023-06-16 05:30:14 +04:00
bool IsPaused() const {
return m_is_running && m_is_paused;
}
2023-05-31 10:37:04 +04:00
const Core::PerfStatsResults& PerfStats() const {
std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex);
return m_perf_stats;
}
void SurfaceChanged() {
if (!IsRunning()) {
return;
}
m_window->OnSurfaceChanged(m_native_window);
}
2023-08-26 01:54:37 +04:00
void ConfigureFilesystemProvider(const std::string& filepath) {
const auto file = m_system.GetFilesystem()->OpenFile(filepath, FileSys::Mode::Read);
if (!file) {
return;
}
auto loader = Loader::GetLoader(m_system, file);
if (!loader) {
return;
}
const auto file_type = loader->GetFileType();
if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) {
return;
}
u64 program_id = 0;
const auto res2 = loader->ReadProgramId(program_id);
if (res2 == Loader::ResultStatus::Success && file_type == Loader::FileType::NCA) {
m_manual_provider->AddEntry(FileSys::TitleType::Application,
FileSys::GetCRTypeFromNCAType(FileSys::NCA{file}.GetType()),
program_id, file);
} else if (res2 == Loader::ResultStatus::Success &&
(file_type == Loader::FileType::XCI || file_type == Loader::FileType::NSP)) {
const auto nsp = file_type == Loader::FileType::NSP
? std::make_shared<FileSys::NSP>(file)
: FileSys::XCI{file}.GetSecurePartitionNSP();
for (const auto& title : nsp->GetNCAs()) {
for (const auto& entry : title.second) {
m_manual_provider->AddEntry(entry.first.first, entry.first.second, title.first,
entry.second->GetBaseFile());
}
}
}
}
2023-05-31 10:37:04 +04:00
Core::SystemResultStatus InitializeEmulation(const std::string& filepath) {
std::scoped_lock lock(m_mutex);
// Create the render window.
m_window = std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window,
m_vulkan_library);
2023-06-13 08:23:21 +04:00
m_system.SetFilesystem(m_vfs);
2023-09-10 23:22:54 +04:00
m_system.GetUserChannel().clear();
2023-06-13 08:23:21 +04:00
2023-05-31 10:37:04 +04:00
// Initialize system.
2023-06-27 00:11:43 +04:00
jauto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>();
2023-05-31 10:37:04 +04:00
m_software_keyboard = android_keyboard.get();
m_system.SetShuttingDown(false);
m_system.ApplySettings();
2023-06-23 01:50:20 +04:00
Settings::LogSettings();
2023-05-31 10:37:04 +04:00
m_system.HIDCore().ReloadInputDevices();
m_system.SetAppletFrontendSet({
nullptr, // Amiibo Settings
nullptr, // Controller Selector
nullptr, // Error Display
nullptr, // Mii Editor
nullptr, // Parental Controls
nullptr, // Photo Viewer
nullptr, // Profile Selector
std::move(android_keyboard), // Software Keyboard
nullptr, // Web Browser
});
2023-08-26 01:54:37 +04:00
// Initialize filesystem.
m_manual_provider = std::make_unique<FileSys::ManualContentProvider>();
2023-06-13 08:23:21 +04:00
m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
2023-08-26 01:54:37 +04:00
m_system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual,
m_manual_provider.get());
2023-06-13 08:23:21 +04:00
m_system.GetFileSystemController().CreateFactories(*m_vfs);
2023-08-26 01:54:37 +04:00
ConfigureFilesystemProvider(filepath);
2023-05-31 10:37:04 +04:00
// Initialize account manager
m_profile_manager = std::make_unique<Service::Account::ProfileManager>();
// Load the ROM.
m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath);
if (m_load_result != Core::SystemResultStatus::Success) {
return m_load_result;
}
// Complete initialization.
m_system.GPU().Start();
m_system.GetCpuManager().OnGpuReady();
m_system.RegisterExitCallback([&] { HaltEmulation(); });
return Core::SystemResultStatus::Success;
}
void ShutdownEmulation() {
std::scoped_lock lock(m_mutex);
m_is_running = false;
// Unload user input.
m_system.HIDCore().UnloadInputDevices();
// Shutdown the main emulated process
if (m_load_result == Core::SystemResultStatus::Success) {
m_system.DetachDebugger();
m_system.ShutdownMainProcess();
m_detached_tasks.WaitForAllTasks();
m_load_result = Core::SystemResultStatus::ErrorNotInitialized;
2023-09-15 09:26:52 +04:00
m_window.reset();
OnEmulationStopped(Core::SystemResultStatus::Success);
return;
2023-05-31 10:37:04 +04:00
}
// Tear down the render window.
m_window.reset();
}
void PauseEmulation() {
std::scoped_lock lock(m_mutex);
m_system.Pause();
2023-06-16 05:30:14 +04:00
m_is_paused = true;
2023-05-31 10:37:04 +04:00
}
void UnPauseEmulation() {
std::scoped_lock lock(m_mutex);
m_system.Run();
2023-06-16 05:30:14 +04:00
m_is_paused = false;
2023-05-31 10:37:04 +04:00
}
void HaltEmulation() {
std::scoped_lock lock(m_mutex);
m_is_running = false;
m_cv.notify_one();
}
void RunEmulation() {
{
std::scoped_lock lock(m_mutex);
m_is_running = true;
}
// Load the disk shader cache.
if (Settings::values.use_disk_shader_cache.GetValue()) {
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
m_system.Renderer().ReadRasterizer()->LoadDiskResources(
m_system.GetApplicationProcessProgramID(), std::stop_token{},
LoadDiskCacheProgress);
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
}
void(m_system.Run());
if (m_system.DebuggerEnabled()) {
m_system.InitializeDebugger();
}
2023-08-31 02:14:34 +04:00
OnEmulationStarted();
2023-05-31 10:37:04 +04:00
while (true) {
{
2023-06-27 00:11:43 +04:00
[[maybe_unused]] std::unique_lock lock(m_mutex);
2023-05-31 10:37:04 +04:00
if (m_cv.wait_for(lock, std::chrono::milliseconds(800),
[&]() { return !m_is_running; })) {
// Emulation halted.
break;
}
}
{
// Refresh performance stats.
std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex);
m_perf_stats = m_system.GetAndResetPerfStats();
}
}
}
std::string GetRomTitle(const std::string& path) {
return GetRomMetadata(path).title;
}
std::vector<u8> GetRomIcon(const std::string& path) {
return GetRomMetadata(path).icon;
}
2023-06-10 12:26:16 +04:00
bool GetIsHomebrew(const std::string& path) {
return GetRomMetadata(path).isHomebrew;
}
2023-05-31 10:37:04 +04:00
void ResetRomMetadata() {
m_rom_metadata_cache.clear();
}
bool IsHandheldOnly() {
2023-06-27 00:11:43 +04:00
jconst npad_style_set = m_system.HIDCore().GetSupportedStyleTag();
2023-05-31 10:37:04 +04:00
if (npad_style_set.fullkey == 1) {
return false;
}
if (npad_style_set.handheld == 0) {
return false;
}
2023-08-25 00:11:26 +04:00
return !Settings::IsDockedMode();
2023-05-31 10:37:04 +04:00
}
2023-06-27 00:11:43 +04:00
void SetDeviceType([[maybe_unused]] int index, int type) {
jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
2023-05-31 10:37:04 +04:00
controller->SetNpadStyleIndex(static_cast<Core::HID::NpadStyleIndex>(type));
}
2023-06-27 00:11:43 +04:00
void OnGamepadConnectEvent([[maybe_unused]] int index) {
jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
2023-05-31 10:37:04 +04:00
// Ensure that player1 is configured correctly and handheld disconnected
if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) {
2023-06-27 00:11:43 +04:00
jauto handheld =
2023-05-31 10:37:04 +04:00
m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) {
handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
handheld->Disconnect();
}
}
// Ensure that handheld is configured correctly and player 1 disconnected
if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) {
2023-06-27 00:11:43 +04:00
jauto player1 =
m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
2023-05-31 10:37:04 +04:00
if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) {
player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
player1->Disconnect();
}
}
if (!controller->IsConnected()) {
controller->Connect();
}
}
2023-06-27 00:11:43 +04:00
void OnGamepadDisconnectEvent([[maybe_unused]] int index) {
jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
2023-05-31 10:37:04 +04:00
controller->Disconnect();
}
SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard() {
return m_software_keyboard;
}
private:
struct RomMetadata {
std::string title;
std::vector<u8> icon;
2023-06-10 12:26:16 +04:00
bool isHomebrew;
2023-05-31 10:37:04 +04:00
};
RomMetadata GetRomMetadata(const std::string& path) {
2023-06-27 00:11:43 +04:00
if (jauto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) {
2023-05-31 10:37:04 +04:00
return search->second;
}
return CacheRomMetadata(path);
}
RomMetadata CacheRomMetadata(const std::string& path) {
2023-06-27 00:11:43 +04:00
jconst file = Core::GetGameFileFromPath(m_vfs, path);
jauto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
2023-05-31 10:37:04 +04:00
RomMetadata entry;
loader->ReadTitle(entry.title);
loader->ReadIcon(entry.icon);
2023-06-10 12:26:16 +04:00
if (loader->GetFileType() == Loader::FileType::NRO) {
2023-07-22 11:33:03 +04:00
jauto loader_nro = reinterpret_cast<Loader::AppLoader_NRO*>(loader.get());
2023-06-10 12:26:16 +04:00
entry.isHomebrew = loader_nro->IsHomebrew();
} else {
entry.isHomebrew = false;
}
2023-05-31 10:37:04 +04:00
m_rom_metadata_cache[path] = entry;
return entry;
}
private:
static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max) {
JNIEnv* env = IDCache::GetEnvForThread();
env->CallStaticVoidMethod(IDCache::GetDiskCacheProgressClass(),
IDCache::GetDiskCacheLoadProgress(), static_cast<jint>(stage),
static_cast<jint>(progress), static_cast<jint>(max));
}
2023-08-31 02:14:34 +04:00
static void OnEmulationStarted() {
JNIEnv* env = IDCache::GetEnvForThread();
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),
IDCache::GetOnEmulationStarted());
}
static void OnEmulationStopped(Core::SystemResultStatus result) {
JNIEnv* env = IDCache::GetEnvForThread();
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),
IDCache::GetOnEmulationStopped(), static_cast<jint>(result));
}
2023-05-31 10:37:04 +04:00
private:
static EmulationSession s_instance;
// Frontend management
std::unordered_map<std::string, RomMetadata> m_rom_metadata_cache;
// Window management
std::unique_ptr<EmuWindow_Android> m_window;
ANativeWindow* m_native_window{};
// Core emulation
Core::System m_system;
InputCommon::InputSubsystem m_input_subsystem;
Common::DetachedTasks m_detached_tasks;
Core::PerfStatsResults m_perf_stats{};
2023-06-13 08:23:21 +04:00
std::shared_ptr<FileSys::VfsFilesystem> m_vfs;
2023-05-31 10:37:04 +04:00
Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
2023-08-31 02:14:34 +04:00
std::atomic<bool> m_is_running = false;
std::atomic<bool> m_is_paused = false;
2023-05-31 10:37:04 +04:00
SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
std::unique_ptr<Service::Account::ProfileManager> m_profile_manager;
2023-08-26 01:54:37 +04:00
std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
2023-05-31 10:37:04 +04:00
// GPU driver parameters
std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
// Synchronization
std::condition_variable_any m_cv;
mutable std::mutex m_perf_stats_mutex;
mutable std::mutex m_mutex;
};
/*static*/ EmulationSession EmulationSession::s_instance;
} // Anonymous namespace
static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
Common::Log::Initialize();
Common::Log::SetColorConsoleBackendEnabled(true);
Common::Log::Start();
MicroProfileOnThreadCreate("EmuThread");
SCOPE_EXIT({ MicroProfileShutdown(); });
LOG_INFO(Frontend, "starting");
if (filepath.empty()) {
LOG_CRITICAL(Frontend, "failed to load: filepath empty!");
return Core::SystemResultStatus::ErrorLoader;
}
SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); });
2023-06-27 00:11:43 +04:00
jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath);
2023-05-31 10:37:04 +04:00
if (result != Core::SystemResultStatus::Success) {
return result;
}
EmulationSession::GetInstance().RunEmulation();
return Core::SystemResultStatus::Success;
}
extern "C" {
2023-06-27 00:11:43 +04:00
void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, jobject instance,
[[maybe_unused]] jobject surf) {
2023-05-31 10:37:04 +04:00
EmulationSession::GetInstance().SetNativeWindow(ANativeWindow_fromSurface(env, surf));
EmulationSession::GetInstance().SurfaceChanged();
}
2023-06-27 00:11:43 +04:00
void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, jobject instance) {
2023-05-31 10:37:04 +04:00
ANativeWindow_release(EmulationSession::GetInstance().NativeWindow());
EmulationSession::GetInstance().SetNativeWindow(nullptr);
EmulationSession::GetInstance().SurfaceChanged();
}
2023-06-27 00:11:43 +04:00
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jobject instance,
[[maybe_unused]] jstring j_directory) {
2023-05-31 10:37:04 +04:00
Common::FS::SetAppDirectory(GetJString(env, j_directory));
}
2023-06-27 00:11:43 +04:00
int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject instance,
2023-09-27 22:05:05 +04:00
jstring j_file,
jstring j_file_extension) {
return EmulationSession::GetInstance().InstallFileToNand(GetJString(env, j_file),
GetJString(env, j_file_extension));
2023-06-13 08:23:21 +04:00
}
2023-06-23 19:15:59 +04:00
void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(JNIEnv* env, jclass clazz,
jstring hook_lib_dir,
jstring custom_driver_dir,
jstring custom_driver_name,
jstring file_redirect_dir) {
2023-05-31 10:37:04 +04:00
EmulationSession::GetInstance().InitializeGpuDriver(
GetJString(env, hook_lib_dir), GetJString(env, custom_driver_dir),
GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir));
}
2023-06-22 02:44:12 +04:00
[[maybe_unused]] static bool CheckKgslPresent() {
constexpr auto KgslPath{"/dev/kgsl-3d0"};
return access(KgslPath, F_OK) == 0;
}
[[maybe_unused]] bool SupportsCustomDriver() {
return android_get_device_api_level() >= 28 && CheckKgslPresent();
}
jboolean JNICALL Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_supportsCustomDriverLoading(
2023-06-27 00:11:43 +04:00
JNIEnv* env, jobject instance) {
2023-06-22 02:44:12 +04:00
#ifdef ARCHITECTURE_arm64
// If the KGSL device exists custom drivers can be loaded using adrenotools
return SupportsCustomDriver();
#else
return false;
#endif
}
2023-06-23 19:15:59 +04:00
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env, jclass clazz) {
2023-05-31 10:37:04 +04:00
Core::Crypto::KeyManager::Instance().ReloadKeys();
return static_cast<jboolean>(Core::Crypto::KeyManager::Instance().AreKeysLoaded());
}
2023-06-23 19:15:59 +04:00
void Java_org_yuzu_yuzu_1emu_NativeLibrary_unpauseEmulation(JNIEnv* env, jclass clazz) {
2023-05-31 10:37:04 +04:00
EmulationSession::GetInstance().UnPauseEmulation();
}
2023-06-23 19:15:59 +04:00
void Java_org_yuzu_yuzu_1emu_NativeLibrary_pauseEmulation(JNIEnv* env, jclass clazz) {
2023-05-31 10:37:04 +04:00
EmulationSession::GetInstance().PauseEmulation();
}
2023-06-23 19:15:59 +04:00
void Java_org_yuzu_yuzu_1emu_NativeLibrary_stopEmulation(JNIEnv* env, jclass clazz) {
2023-05-31 10:37:04 +04:00
EmulationSession::GetInstance().HaltEmulation();
}
2023-06-23 19:15:59 +04:00
void Java_org_yuzu_yuzu_1emu_NativeLibrary_resetRomMetadata(JNIEnv* env, jclass clazz) {
2023-05-31 10:37:04 +04:00
EmulationSession::GetInstance().ResetRomMetadata();
}
2023-06-23 19:15:59 +04:00
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isRunning(JNIEnv* env, jclass clazz) {
2023-05-31 10:37:04 +04:00
return static_cast<jboolean>(EmulationSession::GetInstance().IsRunning());
}
2023-06-23 19:15:59 +04:00
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isPaused(JNIEnv* env, jclass clazz) {
2023-06-16 05:30:14 +04:00
return static_cast<jboolean>(EmulationSession::GetInstance().IsPaused());
}
2023-06-23 19:15:59 +04:00
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHandheldOnly(JNIEnv* env, jclass clazz) {
2023-05-31 10:37:04 +04:00
return EmulationSession::GetInstance().IsHandheldOnly();
}
2023-06-23 19:15:59 +04:00
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_setDeviceType(JNIEnv* env, jclass clazz,
2023-05-31 10:37:04 +04:00
jint j_device, jint j_type) {
if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().SetDeviceType(j_device, j_type);
}
return static_cast<jboolean>(true);
}
2023-06-23 19:15:59 +04:00
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadConnectEvent(JNIEnv* env, jclass clazz,
2023-05-31 10:37:04 +04:00
jint j_device) {
if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().OnGamepadConnectEvent(j_device);
}
return static_cast<jboolean>(true);
}
2023-06-23 19:15:59 +04:00
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadDisconnectEvent(JNIEnv* env, jclass clazz,
jint j_device) {
2023-05-31 10:37:04 +04:00
if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().OnGamepadDisconnectEvent(j_device);
}
return static_cast<jboolean>(true);
}
2023-06-23 19:15:59 +04:00
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadButtonEvent(JNIEnv* env, jclass clazz,
2023-06-27 00:11:43 +04:00
jint j_device, jint j_button,
jint action) {
2023-05-31 10:37:04 +04:00
if (EmulationSession::GetInstance().IsRunning()) {
// Ensure gamepad is connected
EmulationSession::GetInstance().OnGamepadConnectEvent(j_device);
EmulationSession::GetInstance().Window().OnGamepadButtonEvent(j_device, j_button,
action != 0);
}
return static_cast<jboolean>(true);
}
2023-06-23 19:15:59 +04:00
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadJoystickEvent(JNIEnv* env, jclass clazz,
2023-05-31 10:37:04 +04:00
jint j_device, jint stick_id,
jfloat x, jfloat y) {
if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().Window().OnGamepadJoystickEvent(j_device, stick_id, x, y);
}
return static_cast<jboolean>(true);
}
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent(
2023-06-23 19:15:59 +04:00
JNIEnv* env, jclass clazz, jint j_device, jlong delta_timestamp, jfloat gyro_x, jfloat gyro_y,
jfloat gyro_z, jfloat accel_x, jfloat accel_y, jfloat accel_z) {
2023-05-31 10:37:04 +04:00
if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().Window().OnGamepadMotionEvent(
j_device, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z);
}
return static_cast<jboolean>(true);
}
2023-06-23 19:15:59 +04:00
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag(JNIEnv* env, jclass clazz,
2023-05-31 10:37:04 +04:00
jbyteArray j_data) {
jboolean isCopy{false};
std::span<u8> data(reinterpret_cast<u8*>(env->GetByteArrayElements(j_data, &isCopy)),
static_cast<size_t>(env->GetArrayLength(j_data)));
if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().Window().OnReadNfcTag(data);
}
return static_cast<jboolean>(true);
}
2023-06-23 19:15:59 +04:00
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onRemoveNfcTag(JNIEnv* env, jclass clazz) {
2023-05-31 10:37:04 +04:00
if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().Window().OnRemoveNfcTag();
}
return static_cast<jboolean>(true);
}
2023-06-23 19:15:59 +04:00
void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchPressed(JNIEnv* env, jclass clazz, jint id,
2023-05-31 10:37:04 +04:00
jfloat x, jfloat y) {
if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().Window().OnTouchPressed(id, x, y);
}
}
2023-06-23 19:15:59 +04:00
void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchMoved(JNIEnv* env, jclass clazz, jint id,
2023-05-31 10:37:04 +04:00
jfloat x, jfloat y) {
if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().Window().OnTouchMoved(id, x, y);
}
}
2023-06-23 19:15:59 +04:00
void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased(JNIEnv* env, jclass clazz, jint id) {
2023-05-31 10:37:04 +04:00
if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().Window().OnTouchReleased(id);
}
}
2023-06-23 19:15:59 +04:00
jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon(JNIEnv* env, jclass clazz,
2023-06-27 00:11:43 +04:00
jstring j_filename) {
jauto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename));
2023-05-31 10:37:04 +04:00
jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size()));
env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon),
reinterpret_cast<jbyte*>(icon_data.data()));
return icon;
}
2023-06-23 19:15:59 +04:00
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getTitle(JNIEnv* env, jclass clazz,
2023-06-27 00:11:43 +04:00
jstring j_filename) {
jauto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename));
2023-05-31 10:37:04 +04:00
return env->NewStringUTF(title.c_str());
}
2023-06-23 19:15:59 +04:00
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDescription(JNIEnv* env, jclass clazz,
2023-05-31 10:37:04 +04:00
jstring j_filename) {
return j_filename;
}
2023-06-23 19:15:59 +04:00
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGameId(JNIEnv* env, jclass clazz,
2023-05-31 10:37:04 +04:00
jstring j_filename) {
return j_filename;
}
2023-06-23 19:15:59 +04:00
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getRegions(JNIEnv* env, jclass clazz,
2023-06-27 00:11:43 +04:00
jstring j_filename) {
2023-05-31 10:37:04 +04:00
return env->NewStringUTF("");
}
2023-06-23 19:15:59 +04:00
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany(JNIEnv* env, jclass clazz,
2023-06-27 00:11:43 +04:00
jstring j_filename) {
2023-05-31 10:37:04 +04:00
return env->NewStringUTF("");
}
2023-06-23 19:15:59 +04:00
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew(JNIEnv* env, jclass clazz,
2023-06-27 00:11:43 +04:00
jstring j_filename) {
2023-06-10 12:26:16 +04:00
return EmulationSession::GetInstance().GetIsHomebrew(GetJString(env, j_filename));
}
2023-06-27 00:11:43 +04:00
void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation(JNIEnv* env, jclass clazz) {
2023-05-31 10:37:04 +04:00
// Create the default config.ini.
Config{};
// Initialize the emulated system.
EmulationSession::GetInstance().System().Initialize();
}
2023-06-23 19:15:59 +04:00
jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass clazz) {
2023-05-31 10:37:04 +04:00
return {};
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z(
2023-06-27 00:11:43 +04:00
JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate) {}
2023-05-31 10:37:04 +04:00
2023-06-23 19:15:59 +04:00
void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings(JNIEnv* env, jclass clazz) {
2023-05-31 10:37:04 +04:00
Config{};
}
2023-06-23 19:15:59 +04:00
void Java_org_yuzu_yuzu_1emu_NativeLibrary_initGameIni(JNIEnv* env, jclass clazz,
2023-05-31 10:37:04 +04:00
jstring j_game_id) {
std::string_view game_id = env->GetStringUTFChars(j_game_id, 0);
env->ReleaseStringUTFChars(j_game_id, game_id.data());
}
2023-06-23 19:15:59 +04:00
jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jclass clazz) {
2023-05-31 10:37:04 +04:00
jdoubleArray j_stats = env->NewDoubleArray(4);
if (EmulationSession::GetInstance().IsRunning()) {
2023-06-27 00:11:43 +04:00
jconst results = EmulationSession::GetInstance().PerfStats();
2023-05-31 10:37:04 +04:00
// Converting the structure into an array makes it easier to pass it to the frontend
double stats[4] = {results.system_fps, results.average_game_fps, results.frametime,
results.emulation_speed};
env->SetDoubleArrayRegion(j_stats, 0, 4, stats);
}
return j_stats;
}
2023-06-23 19:15:59 +04:00
void Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_setSysDirectory(JNIEnv* env,
jclass clazz,
jstring j_path) {}
2023-05-31 10:37:04 +04:00
2023-06-23 19:15:59 +04:00
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2(JNIEnv* env, jclass clazz,
2023-05-31 10:37:04 +04:00
jstring j_path) {
const std::string path = GetJString(env, j_path);
const Core::SystemResultStatus result{RunEmulation(path)};
if (result != Core::SystemResultStatus::Success) {
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),
IDCache::GetExitEmulationActivity(), static_cast<int>(result));
}
}
2023-06-23 19:15:59 +04:00
void Java_org_yuzu_yuzu_1emu_NativeLibrary_logDeviceInfo(JNIEnv* env, jclass clazz) {
2023-05-31 10:37:04 +04:00
LOG_INFO(Frontend, "yuzu Version: {}-{}", Common::g_scm_branch, Common::g_scm_desc);
LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level());
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_submitInlineKeyboardText(JNIEnv* env, jclass clazz,
jstring j_text) {
const std::u16string input = Common::UTF8ToUTF16(GetJString(env, j_text));
EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardText(input);
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_submitInlineKeyboardInput(JNIEnv* env, jclass clazz,
jint j_key_code) {
EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardInput(j_key_code);
}
2023-09-27 22:05:05 +04:00
void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv* env,
jobject instance) {
const auto nand_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir);
auto vfs_nand_dir = EmulationSession::GetInstance().System().GetFilesystem()->OpenDirectory(
Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read);
Service::Account::ProfileManager manager;
const auto user_id = manager.GetUser(static_cast<std::size_t>(0));
ASSERT(user_id);
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
EmulationSession::GetInstance().System(), vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser,
FileSys::SaveDataType::SaveData, 1, user_id->AsU128(), 0);
const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
if (!Common::FS::CreateParentDirs(full_path)) {
LOG_WARNING(Frontend, "Failed to create full path of the default user's save directory");
}
}
2023-05-31 10:37:04 +04:00
} // extern "C"