diff options
Diffstat (limited to 'src/yuzu/main.cpp')
-rw-r--r-- | src/yuzu/main.cpp | 210 |
1 files changed, 157 insertions, 53 deletions
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 270cccc77..4d501a8f9 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -16,7 +16,7 @@ #include "applets/software_keyboard.h" #include "applets/web_browser.h" #include "configuration/configure_input.h" -#include "configuration/configure_per_general.h" +#include "configuration/configure_per_game.h" #include "core/file_sys/vfs.h" #include "core/file_sys/vfs_real.h" #include "core/frontend/applets/general_frontend.h" @@ -56,6 +56,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include <QShortcut> #include <QStatusBar> #include <QSysInfo> +#include <QUrl> #include <QtConcurrent/QtConcurrent> #include <fmt/format.h> @@ -217,7 +218,20 @@ GMainWindow::GMainWindow() LOG_INFO(Frontend, "yuzu Version: {} | {}-{}", yuzu_build_version, Common::g_scm_branch, Common::g_scm_desc); #ifdef ARCHITECTURE_x86_64 - LOG_INFO(Frontend, "Host CPU: {}", Common::GetCPUCaps().cpu_string); + const auto& caps = Common::GetCPUCaps(); + std::string cpu_string = caps.cpu_string; + if (caps.avx || caps.avx2 || caps.avx512) { + cpu_string += " | AVX"; + if (caps.avx512) { + cpu_string += "512"; + } else if (caps.avx2) { + cpu_string += '2'; + } + if (caps.fma || caps.fma4) { + cpu_string += " | FMA"; + } + } + LOG_INFO(Frontend, "Host CPU: {}", cpu_string); #endif LOG_INFO(Frontend, "Host OS: {}", QSysInfo::prettyProductName().toStdString()); LOG_INFO(Frontend, "Host RAM: {:.2f} GB", @@ -520,14 +534,36 @@ void GMainWindow::InitializeWidgets() { if (emulation_running) { return; } - Settings::values.use_asynchronous_gpu_emulation = - !Settings::values.use_asynchronous_gpu_emulation; - async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation); + bool is_async = !Settings::values.use_asynchronous_gpu_emulation.GetValue() || + Settings::values.use_multi_core.GetValue(); + Settings::values.use_asynchronous_gpu_emulation.SetValue(is_async); + async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue()); Settings::Apply(); }); async_status_button->setText(tr("ASYNC")); async_status_button->setCheckable(true); - async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation); + async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue()); + + // Setup Multicore button + multicore_status_button = new QPushButton(); + multicore_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton")); + multicore_status_button->setFocusPolicy(Qt::NoFocus); + connect(multicore_status_button, &QPushButton::clicked, [&] { + if (emulation_running) { + return; + } + Settings::values.use_multi_core.SetValue(!Settings::values.use_multi_core.GetValue()); + bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue() || + Settings::values.use_multi_core.GetValue(); + Settings::values.use_asynchronous_gpu_emulation.SetValue(is_async); + async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue()); + multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue()); + Settings::Apply(); + }); + multicore_status_button->setText(tr("MULTICORE")); + multicore_status_button->setCheckable(true); + multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue()); + statusBar()->insertPermanentWidget(0, multicore_status_button); statusBar()->insertPermanentWidget(0, async_status_button); // Setup Renderer API button @@ -545,16 +581,16 @@ void GMainWindow::InitializeWidgets() { renderer_status_button->setCheckable(false); renderer_status_button->setDisabled(true); #else - renderer_status_button->setChecked(Settings::values.renderer_backend == + renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::Vulkan); connect(renderer_status_button, &QPushButton::clicked, [=] { if (emulation_running) { return; } if (renderer_status_button->isChecked()) { - Settings::values.renderer_backend = Settings::RendererBackend::Vulkan; + Settings::values.renderer_backend.SetValue(Settings::RendererBackend::Vulkan); } else { - Settings::values.renderer_backend = Settings::RendererBackend::OpenGL; + Settings::values.renderer_backend.SetValue(Settings::RendererBackend::OpenGL); } Settings::Apply(); @@ -653,6 +689,11 @@ void GMainWindow::InitializeHotkeys() { ui.action_Capture_Screenshot->setShortcutContext( hotkey_registry.GetShortcutContext(main_window, capture_screenshot)); + ui.action_Fullscreen->setShortcut( + hotkey_registry.GetHotkey(main_window, fullscreen, this)->key()); + ui.action_Fullscreen->setShortcutContext( + hotkey_registry.GetShortcutContext(main_window, fullscreen)); + connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this), &QShortcut::activated, this, &GMainWindow::OnMenuLoadFile); connect( @@ -686,24 +727,24 @@ void GMainWindow::InitializeHotkeys() { }); connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Speed Limit"), this), &QShortcut::activated, this, [&] { - Settings::values.use_frame_limit = !Settings::values.use_frame_limit; + Settings::values.use_frame_limit.SetValue( + !Settings::values.use_frame_limit.GetValue()); UpdateStatusBar(); }); - // TODO: Remove this comment/static whenever the next major release of - // MSVC occurs and we make it a requirement (see: - // https://developercommunity.visualstudio.com/content/problem/93922/constexprs-are-trying-to-be-captured-in-lambda-fun.html) - static constexpr u16 SPEED_LIMIT_STEP = 5; + constexpr u16 SPEED_LIMIT_STEP = 5; connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Increase Speed Limit"), this), &QShortcut::activated, this, [&] { - if (Settings::values.frame_limit < 9999 - SPEED_LIMIT_STEP) { - Settings::values.frame_limit += SPEED_LIMIT_STEP; + if (Settings::values.frame_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) { + Settings::values.frame_limit.SetValue(SPEED_LIMIT_STEP + + Settings::values.frame_limit.GetValue()); UpdateStatusBar(); } }); connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Decrease Speed Limit"), this), &QShortcut::activated, this, [&] { - if (Settings::values.frame_limit > SPEED_LIMIT_STEP) { - Settings::values.frame_limit -= SPEED_LIMIT_STEP; + if (Settings::values.frame_limit.GetValue() > SPEED_LIMIT_STEP) { + Settings::values.frame_limit.SetValue(Settings::values.frame_limit.GetValue() - + SPEED_LIMIT_STEP); UpdateStatusBar(); } }); @@ -715,7 +756,7 @@ void GMainWindow::InitializeHotkeys() { }); connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Capture Screenshot"), this), &QShortcut::activated, this, [&] { - if (emu_thread->IsRunning()) { + if (emu_thread != nullptr && emu_thread->IsRunning()) { OnCaptureScreenshot(); } }); @@ -726,6 +767,9 @@ void GMainWindow::InitializeHotkeys() { Settings::values.use_docked_mode); dock_status_button->setChecked(Settings::values.use_docked_mode); }); + connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Mute Audio"), this), + &QShortcut::activated, this, + [] { Settings::values.audio_muted = !Settings::values.audio_muted; }); } void GMainWindow::SetDefaultUIGeometry() { @@ -826,6 +870,10 @@ void GMainWindow::ConnectMenuEvents() { connect(ui.action_Stop, &QAction::triggered, this, &GMainWindow::OnStopGame); connect(ui.action_Report_Compatibility, &QAction::triggered, this, &GMainWindow::OnMenuReportCompatibility); + connect(ui.action_Open_Mods_Page, &QAction::triggered, this, &GMainWindow::OnOpenModsPage); + connect(ui.action_Open_Quickstart_Guide, &QAction::triggered, this, + &GMainWindow::OnOpenQuickstartGuide); + connect(ui.action_Open_FAQ, &QAction::triggered, this, &GMainWindow::OnOpenFAQ); connect(ui.action_Restart, &QAction::triggered, this, [this] { BootGame(QString(game_path)); }); connect(ui.action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure); @@ -839,10 +887,6 @@ void GMainWindow::ConnectMenuEvents() { connect(ui.action_Reset_Window_Size, &QAction::triggered, this, &GMainWindow::ResetWindowSize); // Fullscreen - ui.action_Fullscreen->setShortcut( - hotkey_registry - .GetHotkey(QStringLiteral("Main Window"), QStringLiteral("Fullscreen"), this) - ->key()); connect(ui.action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen); // Movie @@ -910,6 +954,8 @@ bool GMainWindow::LoadROM(const QString& filename) { nullptr, // E-Commerce }); + system.RegisterHostThread(); + const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; const auto drd_callout = @@ -996,6 +1042,17 @@ void GMainWindow::BootGame(const QString& filename) { LOG_INFO(Frontend, "yuzu starting..."); StoreRecentFile(filename); // Put the filename on top of the list + u64 title_id{0}; + + const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); + const auto loader = Loader::GetLoader(v_file); + if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) { + // Load per game settings + Config per_game_config(fmt::format("{:016X}.ini", title_id), false); + } + + Settings::LogSettings(); + if (UISettings::values.select_user_on_boot) { SelectAndSetCurrentUser(); } @@ -1020,12 +1077,14 @@ void GMainWindow::BootGame(const QString& filename) { &LoadingScreen::OnLoadProgress, Qt::QueuedConnection); // Update the GUI + UpdateStatusButtons(); if (ui.action_Single_Window_Mode->isChecked()) { game_list->hide(); game_list_placeholder->hide(); } status_bar_update_timer.start(2000); async_status_button->setDisabled(true); + multicore_status_button->setDisabled(true); renderer_status_button->setDisabled(true); if (UISettings::values.hide_mouse) { @@ -1034,20 +1093,20 @@ void GMainWindow::BootGame(const QString& filename) { ui.centralwidget->setMouseTracking(true); } - const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); - std::string title_name; + std::string title_version; const auto res = Core::System::GetInstance().GetGameName(title_name); - if (res != Loader::ResultStatus::Success) { - const auto metadata = FileSys::PatchManager(title_id).GetControlMetadata(); - if (metadata.first != nullptr) - title_name = metadata.first->GetApplicationName(); - if (title_name.empty()) - title_name = FileUtil::GetFilename(filename.toStdString()); + const auto metadata = FileSys::PatchManager(title_id).GetControlMetadata(); + if (metadata.first != nullptr) { + title_version = metadata.first->GetVersionString(); + title_name = metadata.first->GetApplicationName(); + } + if (res != Loader::ResultStatus::Success || title_name.empty()) { + title_name = FileUtil::GetFilename(filename.toStdString()); } - LOG_INFO(Frontend, "Booting game: {:016X} | {}", title_id, title_name); - UpdateWindowTitle(QString::fromStdString(title_name)); + LOG_INFO(Frontend, "Booting game: {:016X} | {} | {}", title_id, title_name, title_version); + UpdateWindowTitle(title_name, title_version); loading_screen->Prepare(Core::System::GetInstance().GetAppLoader()); loading_screen->show(); @@ -1113,6 +1172,7 @@ void GMainWindow::ShutdownGame() { game_fps_label->setVisible(false); emu_frametime_label->setVisible(false); async_status_button->setEnabled(true); + multicore_status_button->setEnabled(true); #ifdef HAS_VULKAN renderer_status_button->setEnabled(true); #endif @@ -1474,7 +1534,7 @@ void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) { return; } - ConfigurePerGameGeneral dialog(this, title_id); + ConfigurePerGame dialog(this, title_id); dialog.LoadFromFile(v_file); auto result = dialog.exec(); if (result == QDialog::Accepted) { @@ -1485,7 +1545,14 @@ void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) { game_list->PopulateAsync(UISettings::values.game_dirs); } - config->Save(); + // Do not cause the global config to write local settings into the config file + Settings::RestoreGlobalState(); + + if (!Core::System::GetInstance().IsPoweredOn()) { + config->Save(); + } + } else { + Settings::RestoreGlobalState(); } } @@ -1772,6 +1839,9 @@ void GMainWindow::OnStopGame() { } ShutdownGame(); + + Settings::RestoreGlobalState(); + UpdateStatusButtons(); } void GMainWindow::OnLoadComplete() { @@ -1797,6 +1867,26 @@ void GMainWindow::OnMenuReportCompatibility() { } } +void GMainWindow::OpenURL(const QUrl& url) { + const bool open = QDesktopServices::openUrl(url); + if (!open) { + QMessageBox::warning(this, tr("Error opening URL"), + tr("Unable to open the URL \"%1\".").arg(url.toString())); + } +} + +void GMainWindow::OnOpenModsPage() { + OpenURL(QUrl(QStringLiteral("https://github.com/yuzu-emu/yuzu/wiki/Switch-Mods"))); +} + +void GMainWindow::OnOpenQuickstartGuide() { + OpenURL(QUrl(QStringLiteral("https://yuzu-emu.org/help/quickstart/"))); +} + +void GMainWindow::OnOpenFAQ() { + OpenURL(QUrl(QStringLiteral("https://yuzu-emu.org/wiki/faq/"))); +} + void GMainWindow::ToggleFullscreen() { if (!emulation_running) { return; @@ -1859,7 +1949,7 @@ void GMainWindow::ToggleWindowMode() { void GMainWindow::ResetWindowSize() { const auto aspect_ratio = Layout::EmulationAspectRatio( - static_cast<Layout::AspectRatio>(Settings::values.aspect_ratio), + static_cast<Layout::AspectRatio>(Settings::values.aspect_ratio.GetValue()), static_cast<float>(Layout::ScreenUndocked::Height) / Layout::ScreenUndocked::Width); if (!ui.action_Single_Window_Mode->isChecked()) { render_window->resize(Layout::ScreenUndocked::Height / aspect_ratio, @@ -1907,12 +1997,7 @@ void GMainWindow::OnConfigure() { ui.centralwidget->setMouseTracking(false); } - dock_status_button->setChecked(Settings::values.use_docked_mode); - async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation); -#ifdef HAS_VULKAN - renderer_status_button->setChecked(Settings::values.renderer_backend == - Settings::RendererBackend::Vulkan); -#endif + UpdateStatusButtons(); } void GMainWindow::OnLoadAmiibo() { @@ -1995,7 +2080,8 @@ void GMainWindow::OnCaptureScreenshot() { OnStartGame(); } -void GMainWindow::UpdateWindowTitle(const QString& title_name) { +void GMainWindow::UpdateWindowTitle(const std::string& title_name, + const std::string& title_version) { const auto full_name = std::string(Common::g_build_fullname); const auto branch_name = std::string(Common::g_scm_branch); const auto description = std::string(Common::g_scm_desc); @@ -2004,7 +2090,7 @@ void GMainWindow::UpdateWindowTitle(const QString& title_name) { const auto date = QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd")).toStdString(); - if (title_name.isEmpty()) { + if (title_name.empty()) { const auto fmt = std::string(Common::g_title_bar_format_idle); setWindowTitle(QString::fromStdString(fmt::format(fmt.empty() ? "yuzu {0}| {1}-{2}" : fmt, full_name, branch_name, description, @@ -2012,8 +2098,8 @@ void GMainWindow::UpdateWindowTitle(const QString& title_name) { } else { const auto fmt = std::string(Common::g_title_bar_format_running); setWindowTitle(QString::fromStdString( - fmt::format(fmt.empty() ? "yuzu {0}| {3} | {1}-{2}" : fmt, full_name, branch_name, - description, title_name.toStdString(), date, build_id))); + fmt::format(fmt.empty() ? "yuzu {0}| {3} | {6} | {1}-{2}" : fmt, full_name, branch_name, + description, title_name, date, build_id, title_version))); } } @@ -2025,21 +2111,34 @@ void GMainWindow::UpdateStatusBar() { auto results = Core::System::GetInstance().GetAndResetPerfStats(); - if (Settings::values.use_frame_limit) { + if (Settings::values.use_frame_limit.GetValue()) { emu_speed_label->setText(tr("Speed: %1% / %2%") .arg(results.emulation_speed * 100.0, 0, 'f', 0) - .arg(Settings::values.frame_limit)); + .arg(Settings::values.frame_limit.GetValue())); } else { emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0)); } game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 0)); emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2)); - emu_speed_label->setVisible(true); + emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue()); game_fps_label->setVisible(true); emu_frametime_label->setVisible(true); } +void GMainWindow::UpdateStatusButtons() { + dock_status_button->setChecked(Settings::values.use_docked_mode); + multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue()); + Settings::values.use_asynchronous_gpu_emulation.SetValue( + Settings::values.use_asynchronous_gpu_emulation.GetValue() || + Settings::values.use_multi_core.GetValue()); + async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue()); +#ifdef HAS_VULKAN + renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() == + Settings::RendererBackend::Vulkan); +#endif +} + void GMainWindow::HideMouseCursor() { if (emu_thread == nullptr || UISettings::values.hide_mouse == false) { mouse_hide_timer.stop(); @@ -2123,6 +2222,9 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det if (answer == QMessageBox::Yes) { if (emu_thread) { ShutdownGame(); + + Settings::RestoreGlobalState(); + UpdateStatusButtons(); } } else { // Only show the message if the game is still running. @@ -2154,7 +2256,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { "title.keys_autogenerated"); } - Core::Crypto::KeyManager keys{}; + Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); if (keys.BaseDeriveNecessary()) { Core::Crypto::PartitionDataManager pdm{vfs->OpenDirectory( FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir), FileSys::Mode::Read)}; @@ -2285,9 +2387,13 @@ void GMainWindow::closeEvent(QCloseEvent* event) { hotkey_registry.SaveHotkeys(); // Shutdown session if the emu thread is active... - if (emu_thread != nullptr) + if (emu_thread != nullptr) { ShutdownGame(); + Settings::RestoreGlobalState(); + UpdateStatusButtons(); + } + render_window->close(); QWidget::closeEvent(event); @@ -2467,8 +2573,6 @@ int main(int argc, char* argv[]) { QObject::connect(&app, &QGuiApplication::applicationStateChanged, &main_window, &GMainWindow::OnAppFocusStateChanged); - Settings::LogSettings(); - int result = app.exec(); detached_tasks.WaitForAllTasks(); return result; |