|
|
|
@ -112,11 +112,10 @@ struct System::Impl { |
|
|
|
u64 program_id; |
|
|
|
|
|
|
|
void Initialize(System& system) { |
|
|
|
device_memory = std::make_unique<Core::DeviceMemory>(); |
|
|
|
device_memory.emplace(); |
|
|
|
|
|
|
|
is_multicore = Settings::values.use_multi_core.GetValue(); |
|
|
|
extended_memory_layout = |
|
|
|
Settings::values.memory_layout_mode.GetValue() != Settings::MemoryLayout::Memory_4Gb; |
|
|
|
extended_memory_layout = Settings::values.memory_layout_mode.GetValue() != Settings::MemoryLayout::Memory_4Gb; |
|
|
|
|
|
|
|
core_timing.SetMulticore(is_multicore); |
|
|
|
core_timing.Initialize([&system]() { system.RegisterHostThread(); }); |
|
|
|
@ -132,7 +131,7 @@ struct System::Impl { |
|
|
|
// Create default implementations of applets if one is not provided.
|
|
|
|
frontend_applets.SetDefaultAppletsIfMissing(); |
|
|
|
|
|
|
|
is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue(); |
|
|
|
auto const is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue(); |
|
|
|
|
|
|
|
kernel.SetMulticore(is_multicore); |
|
|
|
cpu_manager.SetMulticore(is_multicore); |
|
|
|
@ -254,7 +253,7 @@ struct System::Impl { |
|
|
|
} |
|
|
|
|
|
|
|
void InitializeDebugger(System& system, u16 port) { |
|
|
|
debugger = std::make_unique<Debugger>(system, port); |
|
|
|
debugger.emplace(system, port); |
|
|
|
} |
|
|
|
|
|
|
|
void InitializeKernel(System& system) { |
|
|
|
@ -268,24 +267,22 @@ struct System::Impl { |
|
|
|
} |
|
|
|
|
|
|
|
SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) { |
|
|
|
host1x_core = std::make_unique<Tegra::Host1x::Host1x>(system); |
|
|
|
host1x_core.emplace(system); |
|
|
|
gpu_core = VideoCore::CreateGPU(emu_window, system); |
|
|
|
if (!gpu_core) { |
|
|
|
if (!gpu_core) |
|
|
|
return SystemResultStatus::ErrorVideoCore; |
|
|
|
} |
|
|
|
|
|
|
|
audio_core = std::make_unique<AudioCore::AudioCore>(system); |
|
|
|
audio_core.emplace(system); |
|
|
|
|
|
|
|
service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); |
|
|
|
services = |
|
|
|
std::make_unique<Service::Services>(service_manager, system, stop_event.get_token()); |
|
|
|
services.emplace(service_manager, system, stop_event.get_token()); |
|
|
|
|
|
|
|
is_powered_on = true; |
|
|
|
exit_locked = false; |
|
|
|
exit_requested = false; |
|
|
|
|
|
|
|
if (Settings::values.enable_renderdoc_hotkey) { |
|
|
|
renderdoc_api = std::make_unique<Tools::RenderdocAPI>(); |
|
|
|
renderdoc_api.emplace(); |
|
|
|
} |
|
|
|
|
|
|
|
LOG_DEBUG(Core, "Initialized OK"); |
|
|
|
@ -303,16 +300,11 @@ struct System::Impl { |
|
|
|
// Create the application process
|
|
|
|
Loader::ResultStatus load_result{}; |
|
|
|
std::vector<u8> control; |
|
|
|
auto process = |
|
|
|
Service::AM::CreateApplicationProcess(control, app_loader, load_result, system, file, |
|
|
|
params.program_id, params.program_index); |
|
|
|
|
|
|
|
auto process = Service::AM::CreateApplicationProcess(control, app_loader, load_result, system, file, params.program_id, params.program_index); |
|
|
|
if (load_result != Loader::ResultStatus::Success) { |
|
|
|
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result); |
|
|
|
ShutdownMainProcess(); |
|
|
|
|
|
|
|
return static_cast<SystemResultStatus>( |
|
|
|
static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result)); |
|
|
|
return SystemResultStatus(u32(SystemResultStatus::ErrorLoader) + u32(load_result)); |
|
|
|
} |
|
|
|
|
|
|
|
if (!app_loader) { |
|
|
|
@ -337,8 +329,7 @@ struct System::Impl { |
|
|
|
// Set up the rest of the system.
|
|
|
|
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)}; |
|
|
|
if (init_result != SystemResultStatus::Success) { |
|
|
|
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", |
|
|
|
static_cast<int>(init_result)); |
|
|
|
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", int(init_result)); |
|
|
|
ShutdownMainProcess(); |
|
|
|
return init_result; |
|
|
|
} |
|
|
|
@ -361,24 +352,19 @@ struct System::Impl { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
perf_stats = std::make_unique<PerfStats>(params.program_id); |
|
|
|
perf_stats.emplace(params.program_id); |
|
|
|
// Reset counters and set time origin to current frame
|
|
|
|
GetAndResetPerfStats(); |
|
|
|
perf_stats->BeginSystemFrame(); |
|
|
|
|
|
|
|
std::string title_version; |
|
|
|
const FileSys::PatchManager pm(params.program_id, system.GetFileSystemController(), |
|
|
|
system.GetContentProvider()); |
|
|
|
const auto metadata = pm.GetControlMetadata(); |
|
|
|
if (metadata.first != nullptr) { |
|
|
|
title_version = metadata.first->GetVersionString(); |
|
|
|
} |
|
|
|
const FileSys::PatchManager pm(params.program_id, system.GetFileSystemController(), system.GetContentProvider()); |
|
|
|
auto const metadata = pm.GetControlMetadata(); |
|
|
|
std::string title_version = metadata.first != nullptr ? metadata.first->GetVersionString() : ""; |
|
|
|
|
|
|
|
if (app_loader->ReadProgramId(program_id) != Loader::ResultStatus::Success) { |
|
|
|
LOG_ERROR(Core, "Failed to find program id for ROM"); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
GameSettings::LoadOverrides(program_id, gpu_core->Renderer()); |
|
|
|
if (auto room_member = Network::GetRoomMember().lock()) { |
|
|
|
Network::GameInfo game_info; |
|
|
|
@ -387,9 +373,7 @@ struct System::Impl { |
|
|
|
game_info.version = title_version; |
|
|
|
room_member->SendGameInfo(game_info); |
|
|
|
} |
|
|
|
|
|
|
|
status = SystemResultStatus::Success; |
|
|
|
return status; |
|
|
|
return SystemResultStatus::Success; |
|
|
|
} |
|
|
|
|
|
|
|
void ShutdownMainProcess() { |
|
|
|
@ -448,112 +432,79 @@ struct System::Impl { |
|
|
|
} |
|
|
|
|
|
|
|
Loader::ResultStatus GetGameName(std::string& out) const { |
|
|
|
if (app_loader == nullptr) |
|
|
|
return Loader::ResultStatus::ErrorNotInitialized; |
|
|
|
return app_loader->ReadTitle(out); |
|
|
|
} |
|
|
|
|
|
|
|
void SetStatus(SystemResultStatus new_status, const char* details = nullptr) { |
|
|
|
status = new_status; |
|
|
|
if (details) { |
|
|
|
status_details = details; |
|
|
|
} |
|
|
|
return app_loader ? app_loader->ReadTitle(out) : Loader::ResultStatus::ErrorNotInitialized; |
|
|
|
} |
|
|
|
|
|
|
|
PerfStatsResults GetAndResetPerfStats() { |
|
|
|
return perf_stats->GetAndResetStats(core_timing.GetGlobalTimeUs()); |
|
|
|
} |
|
|
|
|
|
|
|
mutable std::mutex suspend_guard; |
|
|
|
std::atomic_bool is_paused{}; |
|
|
|
std::atomic<bool> is_shutting_down{}; |
|
|
|
|
|
|
|
Timing::CoreTiming core_timing; |
|
|
|
Kernel::KernelCore kernel; |
|
|
|
/// RealVfsFilesystem instance
|
|
|
|
FileSys::VirtualFilesystem virtual_filesystem; |
|
|
|
/// ContentProviderUnion instance
|
|
|
|
std::unique_ptr<FileSys::ContentProviderUnion> content_provider; |
|
|
|
Service::FileSystem::FileSystemController fs_controller; |
|
|
|
/// AppLoader used to load the current executing application
|
|
|
|
std::unique_ptr<Loader::AppLoader> app_loader; |
|
|
|
std::unique_ptr<Tegra::GPU> gpu_core; |
|
|
|
std::unique_ptr<Tegra::Host1x::Host1x> host1x_core; |
|
|
|
std::unique_ptr<Core::DeviceMemory> device_memory; |
|
|
|
std::unique_ptr<AudioCore::AudioCore> audio_core; |
|
|
|
Core::HID::HIDCore hid_core; |
|
|
|
|
|
|
|
CpuManager cpu_manager; |
|
|
|
std::atomic_bool is_powered_on{}; |
|
|
|
bool exit_locked = false; |
|
|
|
bool exit_requested = false; |
|
|
|
|
|
|
|
bool nvdec_active{}; |
|
|
|
|
|
|
|
Reporter reporter; |
|
|
|
std::unique_ptr<Memory::CheatEngine> cheat_engine; |
|
|
|
std::unique_ptr<Tools::Freezer> memory_freezer; |
|
|
|
std::array<u8, 0x20> build_id{}; |
|
|
|
|
|
|
|
std::unique_ptr<Tools::RenderdocAPI> renderdoc_api; |
|
|
|
|
|
|
|
/// Applets
|
|
|
|
Service::AM::AppletManager applet_manager; |
|
|
|
Service::AM::Frontend::FrontendAppletHolder frontend_applets; |
|
|
|
|
|
|
|
/// APM (Performance) services
|
|
|
|
Service::APM::Controller apm_controller{core_timing}; |
|
|
|
|
|
|
|
/// Service State
|
|
|
|
Service::Glue::ARPManager arp_manager; |
|
|
|
Service::Account::ProfileManager profile_manager; |
|
|
|
|
|
|
|
/// Service manager
|
|
|
|
std::shared_ptr<Service::SM::ServiceManager> service_manager; |
|
|
|
|
|
|
|
/// Services
|
|
|
|
std::unique_ptr<Service::Services> services; |
|
|
|
|
|
|
|
/// Network instance
|
|
|
|
Network::NetworkInstance network_instance; |
|
|
|
|
|
|
|
/// Debugger
|
|
|
|
std::unique_ptr<Core::Debugger> debugger; |
|
|
|
|
|
|
|
SystemResultStatus status = SystemResultStatus::Success; |
|
|
|
std::string status_details = ""; |
|
|
|
|
|
|
|
std::unique_ptr<Core::PerfStats> perf_stats; |
|
|
|
Core::SpeedLimiter speed_limiter; |
|
|
|
|
|
|
|
bool is_multicore{}; |
|
|
|
bool is_async_gpu{}; |
|
|
|
bool extended_memory_layout{}; |
|
|
|
|
|
|
|
ExecuteProgramCallback execute_program_callback; |
|
|
|
ExitCallback exit_callback; |
|
|
|
std::stop_source stop_event; |
|
|
|
|
|
|
|
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; |
|
|
|
std::optional<Service::Services> services; |
|
|
|
std::optional<Core::Debugger> debugger; |
|
|
|
std::optional<Service::KernelHelpers::ServiceContext> general_channel_context; |
|
|
|
std::optional<Service::Event> general_channel_event; |
|
|
|
std::optional<Core::PerfStats> perf_stats; |
|
|
|
std::optional<Tegra::Host1x::Host1x> host1x_core; |
|
|
|
std::optional<Core::DeviceMemory> device_memory; |
|
|
|
std::optional<AudioCore::AudioCore> audio_core; |
|
|
|
std::optional<Memory::CheatEngine> cheat_engine; |
|
|
|
std::optional<Tools::Freezer> memory_freezer; |
|
|
|
std::optional<Tools::RenderdocAPI> renderdoc_api; |
|
|
|
|
|
|
|
std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES> gpu_dirty_memory_managers; |
|
|
|
std::vector<std::vector<u8>> user_channel; |
|
|
|
std::vector<std::vector<u8>> general_channel; |
|
|
|
|
|
|
|
std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES> |
|
|
|
gpu_dirty_memory_managers; |
|
|
|
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; |
|
|
|
std::array<u8, 0x20> build_id{}; |
|
|
|
|
|
|
|
std::deque<std::vector<u8>> user_channel; |
|
|
|
/// Service manager
|
|
|
|
std::shared_ptr<Service::SM::ServiceManager> service_manager; |
|
|
|
/// ContentProviderUnion instance
|
|
|
|
std::unique_ptr<FileSys::ContentProviderUnion> content_provider; |
|
|
|
/// AppLoader used to load the current executing application
|
|
|
|
std::unique_ptr<Loader::AppLoader> app_loader; |
|
|
|
std::unique_ptr<Tegra::GPU> gpu_core; |
|
|
|
std::stop_source stop_event; |
|
|
|
|
|
|
|
mutable std::mutex suspend_guard; |
|
|
|
std::mutex general_channel_mutex; |
|
|
|
std::deque<std::vector<u8>> general_channel; |
|
|
|
std::unique_ptr<Service::KernelHelpers::ServiceContext> general_channel_context; // lazy
|
|
|
|
std::unique_ptr<Service::Event> general_channel_event; // lazy
|
|
|
|
bool general_channel_initialized{false}; |
|
|
|
std::atomic_bool is_paused{}; |
|
|
|
std::atomic_bool is_shutting_down{}; |
|
|
|
std::atomic_bool is_powered_on{}; |
|
|
|
bool is_multicore : 1 = false; |
|
|
|
bool extended_memory_layout : 1 = false; |
|
|
|
bool exit_locked : 1 = false; |
|
|
|
bool exit_requested : 1 = false; |
|
|
|
bool nvdec_active : 1 = false; |
|
|
|
|
|
|
|
void EnsureGeneralChannelInitialized(System& system) { |
|
|
|
if (general_channel_initialized) { |
|
|
|
return; |
|
|
|
if (!general_channel_event) { |
|
|
|
general_channel_context.emplace(system, "GeneralChannel"); |
|
|
|
general_channel_event.emplace(*general_channel_context); |
|
|
|
} |
|
|
|
general_channel_context = std::make_unique<Service::KernelHelpers::ServiceContext>(system, "GeneralChannel"); |
|
|
|
general_channel_event = std::make_unique<Service::Event>(*general_channel_context); |
|
|
|
general_channel_initialized = true; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
@ -776,14 +727,6 @@ Loader::ResultStatus System::GetGameName(std::string& out) const { |
|
|
|
return impl->GetGameName(out); |
|
|
|
} |
|
|
|
|
|
|
|
void System::SetStatus(SystemResultStatus new_status, const char* details) { |
|
|
|
impl->SetStatus(new_status, details); |
|
|
|
} |
|
|
|
|
|
|
|
const std::string& System::GetStatusDetails() const { |
|
|
|
return impl->status_details; |
|
|
|
} |
|
|
|
|
|
|
|
Loader::AppLoader& System::GetAppLoader() { |
|
|
|
return *impl->app_loader; |
|
|
|
} |
|
|
|
@ -803,7 +746,7 @@ FileSys::VirtualFilesystem System::GetFilesystem() const { |
|
|
|
void System::RegisterCheatList(const std::vector<Memory::CheatEntry>& list, |
|
|
|
const std::array<u8, 32>& build_id, u64 main_region_begin, |
|
|
|
u64 main_region_size) { |
|
|
|
impl->cheat_engine = std::make_unique<Memory::CheatEngine>(*this, list, build_id); |
|
|
|
impl->cheat_engine.emplace(*this, list, build_id); |
|
|
|
impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size); |
|
|
|
} |
|
|
|
|
|
|
|
@ -964,11 +907,13 @@ void System::ExecuteProgram(std::size_t program_index) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
std::deque<std::vector<u8>>& System::GetUserChannel() { |
|
|
|
/// @brief Gets a reference to the user channel stack.
|
|
|
|
/// It is used to transfer data between programs.
|
|
|
|
std::vector<std::vector<u8>>& System::GetUserChannel() { |
|
|
|
return impl->user_channel; |
|
|
|
} |
|
|
|
|
|
|
|
std::deque<std::vector<u8>>& System::GetGeneralChannel() { |
|
|
|
std::vector<std::vector<u8>>& System::GetGeneralChannel() { |
|
|
|
return impl->general_channel; |
|
|
|
} |
|
|
|
|
|
|
|
@ -984,7 +929,7 @@ void System::PushGeneralChannelData(std::vector<u8>&& data) { |
|
|
|
|
|
|
|
bool System::TryPopGeneralChannel(std::vector<u8>& out_data) { |
|
|
|
std::scoped_lock lk{impl->general_channel_mutex}; |
|
|
|
if (!impl->general_channel_initialized || impl->general_channel.empty()) { |
|
|
|
if (!impl->general_channel_event || impl->general_channel.empty()) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
out_data = std::move(impl->general_channel.back()); |
|
|
|
|