android: Use header for EmulationSession

This commit is contained in:
Charles Lombardo 2023-10-24 17:00:15 -04:00
parent 79d3cef8db
commit 1e61c3e1e7
3 changed files with 444 additions and 458 deletions

View file

@ -14,6 +14,7 @@ add_library(yuzu-android SHARED
id_cache.cpp id_cache.cpp
id_cache.h id_cache.h
native.cpp native.cpp
native.h
native_config.cpp native_config.cpp
uisettings.cpp uisettings.cpp
) )

View file

@ -33,7 +33,6 @@
#include "core/crypto/key_manager.h" #include "core/crypto/key_manager.h"
#include "core/file_sys/card_image.h" #include "core/file_sys/card_image.h"
#include "core/file_sys/content_archive.h" #include "core/file_sys/content_archive.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/submission_package.h" #include "core/file_sys/submission_package.h"
#include "core/file_sys/vfs.h" #include "core/file_sys/vfs.h"
#include "core/file_sys/vfs_real.h" #include "core/file_sys/vfs_real.h"
@ -48,63 +47,55 @@
#include "core/hid/emulated_controller.h" #include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h" #include "core/hid/hid_core.h"
#include "core/hid/hid_types.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_ae.h"
#include "core/hle/service/am/applet_oe.h" #include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/am/applets/applets.h" #include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h" #include "core/loader/loader.h"
#include "core/perf_stats.h"
#include "jni/android_common/android_common.h" #include "jni/android_common/android_common.h"
#include "jni/applets/software_keyboard.h"
#include "jni/config.h" #include "jni/config.h"
#include "jni/emu_window/emu_window.h"
#include "jni/id_cache.h" #include "jni/id_cache.h"
#include "video_core/rasterizer_interface.h" #include "jni/native.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
#define jconst [[maybe_unused]] const auto #define jconst [[maybe_unused]] const auto
#define jauto [[maybe_unused]] auto #define jauto [[maybe_unused]] auto
namespace { static EmulationSession s_instance;
class EmulationSession final { EmulationSession::EmulationSession() {
public:
EmulationSession() {
m_vfs = std::make_shared<FileSys::RealVfsFilesystem>(); m_vfs = std::make_shared<FileSys::RealVfsFilesystem>();
} }
~EmulationSession() = default; EmulationSession& EmulationSession::GetInstance() {
static EmulationSession& GetInstance() {
return s_instance; return s_instance;
} }
const Core::System& System() const { const Core::System& EmulationSession::System() const {
return m_system; return m_system;
} }
Core::System& System() { Core::System& EmulationSession::System() {
return m_system; return m_system;
} }
const EmuWindow_Android& Window() const { const EmuWindow_Android& EmulationSession::Window() const {
return *m_window; return *m_window;
} }
EmuWindow_Android& Window() { EmuWindow_Android& EmulationSession::Window() {
return *m_window; return *m_window;
} }
ANativeWindow* NativeWindow() const { ANativeWindow* EmulationSession::NativeWindow() const {
return m_native_window; return m_native_window;
} }
void SetNativeWindow(ANativeWindow* native_window) { void EmulationSession::SetNativeWindow(ANativeWindow* native_window) {
m_native_window = native_window; m_native_window = native_window;
} }
int InstallFileToNand(std::string filename, std::string file_extension) { int EmulationSession::InstallFileToNand(std::string filename, std::string file_extension) {
jconst copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, jconst copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest,
std::size_t block_size) { std::size_t block_size) {
if (src == nullptr || dest == nullptr) { if (src == nullptr || dest == nullptr) {
@ -153,8 +144,8 @@ public:
return InstallError; return InstallError;
} }
jconst res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry( jconst res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry(*nsp, true,
*nsp, true, copy_func); copy_func);
switch (res) { switch (res) {
case FileSys::InstallResult::Success: case FileSys::InstallResult::Success:
@ -166,9 +157,10 @@ public:
default: default:
return InstallError; return InstallError;
} }
} }
void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir, void EmulationSession::InitializeGpuDriver(const std::string& hook_lib_dir,
const std::string& custom_driver_dir,
const std::string& custom_driver_name, const std::string& custom_driver_name,
const std::string& file_redirect_dir) { const std::string& file_redirect_dir) {
#ifdef ARCHITECTURE_arm64 #ifdef ARCHITECTURE_arm64
@ -191,36 +183,35 @@ public:
// Try to load the system driver. // Try to load the system driver.
if (!handle) { if (!handle) {
handle = handle = adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(),
adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(),
nullptr, nullptr, file_redirect_dir_, nullptr); nullptr, nullptr, file_redirect_dir_, nullptr);
} }
m_vulkan_library = std::make_shared<Common::DynamicLibrary>(handle); m_vulkan_library = std::make_shared<Common::DynamicLibrary>(handle);
#endif #endif
} }
bool IsRunning() const { bool EmulationSession::IsRunning() const {
return m_is_running; return m_is_running;
} }
bool IsPaused() const { bool EmulationSession::IsPaused() const {
return m_is_running && m_is_paused; return m_is_running && m_is_paused;
} }
const Core::PerfStatsResults& PerfStats() const { const Core::PerfStatsResults& EmulationSession::PerfStats() const {
std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex); std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex);
return m_perf_stats; return m_perf_stats;
} }
void SurfaceChanged() { void EmulationSession::SurfaceChanged() {
if (!IsRunning()) { if (!IsRunning()) {
return; return;
} }
m_window->OnSurfaceChanged(m_native_window); m_window->OnSurfaceChanged(m_native_window);
} }
void ConfigureFilesystemProvider(const std::string& filepath) { void EmulationSession::ConfigureFilesystemProvider(const std::string& filepath) {
const auto file = m_system.GetFilesystem()->OpenFile(filepath, FileSys::Mode::Read); const auto file = m_system.GetFilesystem()->OpenFile(filepath, FileSys::Mode::Read);
if (!file) { if (!file) {
return; return;
@ -254,14 +245,14 @@ public:
} }
} }
} }
} }
Core::SystemResultStatus InitializeEmulation(const std::string& filepath) { Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string& filepath) {
std::scoped_lock lock(m_mutex); std::scoped_lock lock(m_mutex);
// Create the render window. // Create the render window.
m_window = std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window, m_window =
m_vulkan_library); std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window, m_vulkan_library);
m_system.SetFilesystem(m_vfs); m_system.SetFilesystem(m_vfs);
m_system.GetUserChannel().clear(); m_system.GetUserChannel().clear();
@ -308,9 +299,9 @@ public:
m_system.RegisterExitCallback([&] { HaltEmulation(); }); m_system.RegisterExitCallback([&] { HaltEmulation(); });
return Core::SystemResultStatus::Success; return Core::SystemResultStatus::Success;
} }
void ShutdownEmulation() { void EmulationSession::ShutdownEmulation() {
std::scoped_lock lock(m_mutex); std::scoped_lock lock(m_mutex);
m_is_running = false; m_is_running = false;
@ -331,27 +322,27 @@ public:
// Tear down the render window. // Tear down the render window.
m_window.reset(); m_window.reset();
} }
void PauseEmulation() { void EmulationSession::PauseEmulation() {
std::scoped_lock lock(m_mutex); std::scoped_lock lock(m_mutex);
m_system.Pause(); m_system.Pause();
m_is_paused = true; m_is_paused = true;
} }
void UnPauseEmulation() { void EmulationSession::UnPauseEmulation() {
std::scoped_lock lock(m_mutex); std::scoped_lock lock(m_mutex);
m_system.Run(); m_system.Run();
m_is_paused = false; m_is_paused = false;
} }
void HaltEmulation() { void EmulationSession::HaltEmulation() {
std::scoped_lock lock(m_mutex); std::scoped_lock lock(m_mutex);
m_is_running = false; m_is_running = false;
m_cv.notify_one(); m_cv.notify_one();
} }
void RunEmulation() { void EmulationSession::RunEmulation() {
{ {
std::scoped_lock lock(m_mutex); std::scoped_lock lock(m_mutex);
m_is_running = true; m_is_running = true;
@ -361,8 +352,7 @@ public:
if (Settings::values.use_disk_shader_cache.GetValue()) { if (Settings::values.use_disk_shader_cache.GetValue()) {
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
m_system.Renderer().ReadRasterizer()->LoadDiskResources( m_system.Renderer().ReadRasterizer()->LoadDiskResources(
m_system.GetApplicationProcessProgramID(), std::stop_token{}, m_system.GetApplicationProcessProgramID(), std::stop_token{}, LoadDiskCacheProgress);
LoadDiskCacheProgress);
LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0); LoadDiskCacheProgress(VideoCore::LoadCallbackStage::Complete, 0, 0);
} }
@ -389,25 +379,9 @@ public:
m_perf_stats = m_system.GetAndResetPerfStats(); m_perf_stats = m_system.GetAndResetPerfStats();
} }
} }
} }
std::string GetRomTitle(const std::string& path) { bool EmulationSession::IsHandheldOnly() {
return GetRomMetadata(path).title;
}
std::vector<u8> GetRomIcon(const std::string& path) {
return GetRomMetadata(path).icon;
}
bool GetIsHomebrew(const std::string& path) {
return GetRomMetadata(path).isHomebrew;
}
void ResetRomMetadata() {
m_rom_metadata_cache.clear();
}
bool IsHandheldOnly() {
jconst npad_style_set = m_system.HIDCore().GetSupportedStyleTag(); jconst npad_style_set = m_system.HIDCore().GetSupportedStyleTag();
if (npad_style_set.fullkey == 1) { if (npad_style_set.fullkey == 1) {
@ -419,20 +393,19 @@ public:
} }
return !Settings::IsDockedMode(); return !Settings::IsDockedMode();
} }
void SetDeviceType([[maybe_unused]] int index, int type) { void EmulationSession::SetDeviceType([[maybe_unused]] int index, int type) {
jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
controller->SetNpadStyleIndex(static_cast<Core::HID::NpadStyleIndex>(type)); controller->SetNpadStyleIndex(static_cast<Core::HID::NpadStyleIndex>(type));
} }
void OnGamepadConnectEvent([[maybe_unused]] int index) { void EmulationSession::OnGamepadConnectEvent([[maybe_unused]] int index) {
jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
// Ensure that player1 is configured correctly and handheld disconnected // Ensure that player1 is configured correctly and handheld disconnected
if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) { if (controller->GetNpadIdType() == Core::HID::NpadIdType::Player1) {
jauto handheld = jauto handheld = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) { if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) {
handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
@ -443,8 +416,7 @@ public:
// Ensure that handheld is configured correctly and player 1 disconnected // Ensure that handheld is configured correctly and player 1 disconnected
if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) { if (controller->GetNpadIdType() == Core::HID::NpadIdType::Handheld) {
jauto player1 = jauto player1 = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) { if (controller->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::Handheld) {
player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); player1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
@ -456,106 +428,35 @@ public:
if (!controller->IsConnected()) { if (!controller->IsConnected()) {
controller->Connect(); controller->Connect();
} }
} }
void OnGamepadDisconnectEvent([[maybe_unused]] int index) { void EmulationSession::OnGamepadDisconnectEvent([[maybe_unused]] int index) {
jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index); jauto controller = m_system.HIDCore().GetEmulatedControllerByIndex(index);
controller->Disconnect(); controller->Disconnect();
} }
SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard() { SoftwareKeyboard::AndroidKeyboard* EmulationSession::SoftwareKeyboard() {
return m_software_keyboard; return m_software_keyboard;
} }
private: void EmulationSession::LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress,
struct RomMetadata { int max) {
std::string title;
std::vector<u8> icon;
bool isHomebrew;
};
RomMetadata GetRomMetadata(const std::string& path) {
if (jauto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) {
return search->second;
}
return CacheRomMetadata(path);
}
RomMetadata CacheRomMetadata(const std::string& path) {
jconst file = Core::GetGameFileFromPath(m_vfs, path);
jauto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
RomMetadata entry;
loader->ReadTitle(entry.title);
loader->ReadIcon(entry.icon);
if (loader->GetFileType() == Loader::FileType::NRO) {
jauto loader_nro = reinterpret_cast<Loader::AppLoader_NRO*>(loader.get());
entry.isHomebrew = loader_nro->IsHomebrew();
} else {
entry.isHomebrew = false;
}
m_rom_metadata_cache[path] = entry;
return entry;
}
private:
static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max) {
JNIEnv* env = IDCache::GetEnvForThread(); JNIEnv* env = IDCache::GetEnvForThread();
env->CallStaticVoidMethod(IDCache::GetDiskCacheProgressClass(), env->CallStaticVoidMethod(IDCache::GetDiskCacheProgressClass(),
IDCache::GetDiskCacheLoadProgress(), static_cast<jint>(stage), IDCache::GetDiskCacheLoadProgress(), static_cast<jint>(stage),
static_cast<jint>(progress), static_cast<jint>(max)); static_cast<jint>(progress), static_cast<jint>(max));
} }
static void OnEmulationStarted() { void EmulationSession::OnEmulationStarted() {
JNIEnv* env = IDCache::GetEnvForThread(); JNIEnv* env = IDCache::GetEnvForThread();
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetOnEmulationStarted());
IDCache::GetOnEmulationStarted()); }
}
static void OnEmulationStopped(Core::SystemResultStatus result) { void EmulationSession::OnEmulationStopped(Core::SystemResultStatus result) {
JNIEnv* env = IDCache::GetEnvForThread(); JNIEnv* env = IDCache::GetEnvForThread();
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetOnEmulationStopped(),
IDCache::GetOnEmulationStopped(), static_cast<jint>(result)); static_cast<jint>(result));
} }
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{};
std::shared_ptr<FileSys::VfsFilesystem> m_vfs;
Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
std::atomic<bool> m_is_running = false;
std::atomic<bool> m_is_paused = false;
SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
std::unique_ptr<Service::Account::ProfileManager> m_profile_manager;
std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
// 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) { static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
Common::Log::Initialize(); Common::Log::Initialize();

View file

@ -0,0 +1,84 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <android/native_window_jni.h>
#include "core/core.h"
#include "core/perf_stats.h"
#include "jni/emu_window/emu_window.h"
#include "jni/applets/software_keyboard.h"
#include "video_core/rasterizer_interface.h"
#include "common/detached_tasks.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/file_sys/registered_cache.h"
#pragma once
class EmulationSession final {
public:
explicit EmulationSession();
~EmulationSession() = default;
static EmulationSession& GetInstance();
const Core::System& System() const;
Core::System& System();
const EmuWindow_Android& Window() const;
EmuWindow_Android& Window();
ANativeWindow* NativeWindow() const;
void SetNativeWindow(ANativeWindow* native_window);
void SurfaceChanged();
int InstallFileToNand(std::string filename, std::string file_extension);
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);
bool IsRunning() const;
bool IsPaused() const;
void PauseEmulation();
void UnPauseEmulation();
void HaltEmulation();
void RunEmulation();
void ShutdownEmulation();
const Core::PerfStatsResults& PerfStats() const;
void ConfigureFilesystemProvider(const std::string& filepath);
Core::SystemResultStatus InitializeEmulation(const std::string& filepath);
bool IsHandheldOnly();
void SetDeviceType([[maybe_unused]] int index, int type);
void OnGamepadConnectEvent([[maybe_unused]] int index);
void OnGamepadDisconnectEvent([[maybe_unused]] int index);
SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard();
private:
static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max);
static void OnEmulationStarted();
static void OnEmulationStopped(Core::SystemResultStatus result);
private:
// 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{};
std::shared_ptr<FileSys::VfsFilesystem> m_vfs;
Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
std::atomic<bool> m_is_running = false;
std::atomic<bool> m_is_paused = false;
SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
std::unique_ptr<Service::Account::ProfileManager> m_profile_manager;
std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
// 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;
};