mikage-dev/source/session.cpp
2024-09-29 22:28:58 +02:00

121 lines
5.5 KiB
C++

#include "session.hpp"
#include "os.hpp"
#include "processes/pxi_fs.hpp" // Required to check if gamecard has an update partition
#include <loader/gamecard.hpp>
#include <framework/console.hpp>
#include <framework/logging.hpp>
#include <framework/meta_tools.hpp>
#include <framework/profiler.hpp>
#include <framework/settings.hpp>
#include <spdlog/spdlog.h>
#include <memory>
std::unique_ptr<Loader::GameCard> LoadGameCard(spdlog::logger& logger, Settings::Settings& settings) {
// TODO: Move gamecard initialization below setup so that we can gracefully display gamecard loading errors
logger.info("Loading gamecard image");
auto gamecard = Meta::invoke([&]() {
auto&& visitor = [](auto&& val) -> std::unique_ptr<Loader::GameCard> {
if constexpr (std::is_same_v<std::decay_t<decltype(val)>, Settings::InitialApplicationTag::HostFile>) {
try {
if (Loader::GameCardFrom3DSX::IsLoadableFile(val.filename))
return std::unique_ptr<Loader::GameCard> { new Loader::GameCardFrom3DSX(val.filename) };
else if (Loader::GameCardFromCXI::IsLoadableFile(val.filename))
return std::unique_ptr<Loader::GameCard> { new Loader::GameCardFromCXI(val.filename) };
else if (Loader::GameCardFromCCI::IsLoadableFile(val.filename))
return std::unique_ptr<Loader::GameCard> { new Loader::GameCardFromCCI(val.filename) };
} catch (std::ios_base::failure& err) {
throw std::runtime_error(fmt::format("Could not load game file \"{}\"", val.filename));
}
} else if constexpr (std::is_same_v<std::decay_t<decltype(val)>, Settings::InitialApplicationTag::FileDescriptor>) {
if (Loader::GameCardFrom3DSX::IsLoadableFile(val.fd))
return std::unique_ptr<Loader::GameCard> { new Loader::GameCardFrom3DSX(val.fd) };
else if (Loader::GameCardFromCXI::IsLoadableFile(val.fd))
return std::unique_ptr<Loader::GameCard> { new Loader::GameCardFromCXI(val.fd) };
else if (Loader::GameCardFromCCI::IsLoadableFile(val.fd))
return std::unique_ptr<Loader::GameCard> { new Loader::GameCardFromCCI(val.fd) };
} else if constexpr (std::is_same_v<std::decay_t<decltype(val)>, std::monostate>) {
return nullptr;
}
throw std::runtime_error("Unrecognized input file format. Input must be decrypted and in 3DSX, CCI, or CXI format.");
};
return std::visit(visitor, settings.get<Settings::InitialApplicationTag>());
});
if (settings.get<Settings::BootToHomeMenu>() && gamecard) {
try {
// Attempt to open update partition required to boot gamecards from Home Menu.
// If this throws, the partition does not exist (i.e. this is not a CCI file).
// TODO: For CXI files, provide a dummy update partition
gamecard->GetPartitionFromId(Loader::NCSDPartitionId::UpdateData);
} catch (...) {
logger.error("Can't use non-CCI/3DS file when booting home menu. Either redump as CCI or launch this title directly\n");
// TODO: Throw exception instead
std::exit(1);
}
}
return gamecard;
}
EmuSession::EmuSession( LogManager& log_manager, Settings::Settings& settings,
AudioFrontend& audio, VulkanDeviceManager& vulkan_device_manager,
EmuDisplay::EmuDisplay& display, const KeyDatabase& keydb,
std::unique_ptr<Loader::GameCard> gamecard)
: setup(std::make_shared<Interpreter::Setup>(log_manager, keydb, std::move(gamecard), profiler, debug_server)),
pica { log_manager.RegisterLogger("Pica"), debug_server, settings, setup->mem, profiler,
vulkan_device_manager.physical_device, *vulkan_device_manager.device,
vulkan_device_manager.graphics_queue_index, vulkan_device_manager.graphics_queue } {
setup->cpus[0].cpu.cpsr.mode = ARM::InternalProcessorMode::User;
setup->mem.InjectDependency(audio);
std::unique_ptr<ConsoleModule> os_module;
std::tie(setup->os, os_module) = HLE::OS::OS::Create(settings, *setup, log_manager, profiler, audio, pica, display);
for (auto& cpu : setup->cpus)
cpu.os = setup->os.get();
setup->os->Initialize();
pica.InjectDependency(*setup->os.get());
pica.InjectDependency(setup->mem);
setup->mem.InjectDependency(pica);
setup->mem.InjectDependency(input);
// TODO: Check if we can enable this on Android, too
network_console = std::make_unique<NetworkConsole>(12347);
console_thread = std::thread { [os_module=std::move(os_module), &console=*network_console]() mutable {
console.RegisterModule("os", std::move(os_module));
console.Run();
} };
#if ENABLE_PISTACHE
std::thread debug_server_thread([&]() {
try {
debug_server.Run(3001);
} catch (...) {
// QMetaObject::invokeMethod(&window, "onEmulatorException", Qt::BlockingQueuedConnection, Q_ARG(std::exception_ptr, std::current_exception()));
//// emuthread_exception = std::current_exception();
// while(true);
}
});
debug_server_thread.detach();
#endif
}
EmuSession::~EmuSession() {
// Stop NetworkConsole first so that the console thread can return
network_console->Stop();
console_thread.join();
// TODO: Shut down debug_server
}
void EmuSession::Run() {
setup->os->Run(setup);
}