Qt: Deduplicate interface code and reduce core coupling

This enables more code sharing between interfaces in the future (e.g.
nogui, gsrunner, etc). Eventually I'll move everything in Frontend/ to
its own project.

 - VMManager now no longer depends on anything in Frontend.
 - Moved INISettingsInterface out of Frontend.
 - Log settings can now be overridden per-game (if you really want to)..
 - Hotkeys get their own file.
This commit is contained in:
Connor McLaughlin 2022-09-14 22:41:50 +10:00 committed by refractionpcsx2
parent c96f1d28e6
commit 6810a9d593
24 changed files with 525 additions and 361 deletions

View File

@ -309,23 +309,17 @@ void MainWindow::connectSignals()
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionViewStatusBarVerbose, "UI", "VerboseStatusBar", false);
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableSystemConsole, "Logging", "EnableSystemConsole", false);
connect(m_ui.actionEnableSystemConsole, &QAction::triggered, this, &MainWindow::onLoggingOptionChanged);
#ifndef PCSX2_DEVBUILD
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableVerboseLogging, "Logging", "EnableVerbose", false);
connect(m_ui.actionEnableVerboseLogging, &QAction::triggered, this, &MainWindow::onLoggingOptionChanged);
#else
// Dev builds always have verbose logging.
m_ui.actionEnableVerboseLogging->setChecked(true);
m_ui.actionEnableVerboseLogging->setEnabled(false);
#endif
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableEEConsoleLogging, "Logging", "EnableEEConsole", true);
connect(m_ui.actionEnableEEConsoleLogging, &QAction::triggered, this, &MainWindow::onLoggingOptionChanged);
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableIOPConsoleLogging, "Logging", "EnableIOPConsole", true);
connect(m_ui.actionEnableIOPConsoleLogging, &QAction::triggered, this, &MainWindow::onLoggingOptionChanged);
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableFileLogging, "Logging", "EnableFileLogging", false);
connect(m_ui.actionEnableFileLogging, &QAction::triggered, this, &MainWindow::onLoggingOptionChanged);
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableLogTimestamps, "Logging", "EnableTimestamps", true);
connect(m_ui.actionEnableLogTimestamps, &QAction::triggered, this, &MainWindow::onLoggingOptionChanged);
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableCDVDVerboseReads, "EmuCore", "CdvdVerboseReads", false);
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionSaveBlockDump, "EmuCore", "CdvdDumpBlocks", false);
connect(m_ui.actionSaveBlockDump, &QAction::toggled, this, &MainWindow::onBlockDumpActionToggled);
@ -337,9 +331,7 @@ void MainWindow::connectSignals()
connect(m_ui.actionInputRecPlay, &QAction::triggered, this, &MainWindow::onInputRecPlayActionTriggered);
connect(m_ui.actionInputRecStop, &QAction::triggered, this, &MainWindow::onInputRecStopActionTriggered);
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionInputRecConsoleLogs, "Logging", "EnableInputRecordingLogs", false);
connect(m_ui.actionInputRecConsoleLogs, &QAction::triggered, this, &MainWindow::onLoggingOptionChanged);
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionInputRecControllerLogs, "Logging", "EnableControllerLogs", false);
connect(m_ui.actionInputRecControllerLogs, &QAction::triggered, this, &MainWindow::onLoggingOptionChanged);
// These need to be queued connections to stop crashing due to menus opening/closing and switching focus.
connect(m_game_list_widget, &GameListWidget::refreshProgress, this, &MainWindow::onGameListRefreshProgress);
@ -1509,11 +1501,6 @@ void MainWindow::updateTheme()
m_game_list_widget->refreshImages();
}
void MainWindow::onLoggingOptionChanged()
{
Host::UpdateLogging(QtHost::InNoGUIMode());
}
void MainWindow::onInputRecNewActionTriggered()
{
const bool wasPaused = s_vm_paused;

View File

@ -149,7 +149,6 @@ private Q_SLOTS:
void onCheckForUpdatesActionTriggered();
void onToolsOpenDataDirectoryTriggered();
void updateTheme();
void onLoggingOptionChanged();
void onScreenshotActionTriggered();
void onSaveGSDumpActionTriggered();
void onBlockDumpActionToggled(bool checked);

View File

@ -37,13 +37,13 @@
#include "pcsx2/Frontend/GameList.h"
#include "pcsx2/Frontend/InputManager.h"
#include "pcsx2/Frontend/ImGuiManager.h"
#include "pcsx2/Frontend/INISettingsInterface.h"
#include "pcsx2/Frontend/LogSink.h"
#include "pcsx2/GS.h"
#include "pcsx2/GS/GS.h"
#include "pcsx2/GSDumpReplayer.h"
#include "pcsx2/HostDisplay.h"
#include "pcsx2/HostSettings.h"
#include "pcsx2/INISettingsInterface.h"
#include "pcsx2/PAD/Host/PAD.h"
#include "pcsx2/PerformanceMetrics.h"
#include "pcsx2/VMManager.h"
@ -230,14 +230,11 @@ void EmuThread::startVM(std::shared_ptr<VMBootParameters> boot_params)
pxAssertRel(!VMManager::HasValidVM(), "VM is shut down");
// Only initialize fullscreen/render-to-main when we're not running big picture.
if (!m_run_fullscreen_ui)
loadOurInitialSettings();
// Determine whether to start fullscreen or not.
if (boot_params->fullscreen.has_value())
m_is_fullscreen = boot_params->fullscreen.value();
emit onVMStarting();
else
m_is_fullscreen = Host::GetBaseBoolSettingValue("UI", "StartFullscreen", false);
if (!VMManager::Initialize(*boot_params))
return;
@ -359,26 +356,19 @@ void EmuThread::saveStateToSlot(qint32 slot)
void EmuThread::run()
{
Threading::SetNameOfCurrentThread("EmuThread");
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle::GetForCallingThread());
// Qt-specific initialization.
m_event_loop = new QEventLoop();
m_started_semaphore.release();
connectSignals();
// neither of these should ever fail.
if (!VMManager::Internal::InitializeGlobals() || !VMManager::Internal::InitializeMemory())
pxFailRel("Failed to allocate memory map");
// We want settings loaded so we choose the correct renderer for big picture mode.
// This also sorts out input sources.
loadOurSettings();
loadOurInitialSettings();
VMManager::LoadSettings();
// Common host initialization (VM setup, etc).
CommonHost::CPUThreadInitialize();
// Start background polling because the VM won't do it for us.
createBackgroundControllerPollTimer();
startBackgroundControllerPollTimer();
connectSignals();
// Main CPU thread loop.
while (!m_shutdown_flag.load())
{
if (!VMManager::HasValidVM())
@ -390,13 +380,12 @@ void EmuThread::run()
executeVM();
}
// Teardown in reverse order.
stopBackgroundControllerPollTimer();
destroyBackgroundControllerPollTimer();
InputManager::CloseSources();
VMManager::WaitForSaveStateFlush();
VMManager::Internal::ReleaseMemory();
VMManager::Internal::ReleaseGlobals();
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle());
CommonHost::CPUThreadShutdown();
// Move back to the UI thread, since we're no longer running.
moveToThread(m_ui_thread);
deleteLater();
}
@ -410,6 +399,7 @@ void EmuThread::destroyVM()
m_last_internal_height = 0;
m_was_paused_by_focus_loss = false;
VMManager::Shutdown(m_save_state_on_shutdown);
m_save_state_on_shutdown = false;
}
void EmuThread::executeVM()
@ -540,7 +530,6 @@ void EmuThread::applySettings()
return;
}
checkForSettingChanges();
VMManager::ApplySettings();
}
@ -553,11 +542,7 @@ void EmuThread::reloadGameSettings()
}
// this will skip applying settings when they're not active
if (VMManager::ReloadGameSettings())
{
// none of these settings below are per-game.. for now. but in case they are in the future.
checkForSettingChanges();
}
VMManager::ReloadGameSettings();
}
void EmuThread::updateEmuFolders()
@ -571,26 +556,24 @@ void EmuThread::updateEmuFolders()
Host::Internal::UpdateEmuFolders();
}
void EmuThread::loadOurSettings()
{
m_verbose_status = Host::GetBaseBoolSettingValue("UI", "VerboseStatusBar", false);
m_pause_on_focus_loss = Host::GetBaseBoolSettingValue("UI", "PauseOnFocusLoss", false);
}
void EmuThread::connectSignals()
{
connect(qApp, &QGuiApplication::applicationStateChanged, this, &EmuThread::onApplicationStateChanged);
}
void EmuThread::loadOurInitialSettings()
void EmuThread::loadSettings(SettingsInterface& si, std::unique_lock<std::mutex>& lock)
{
m_is_fullscreen = Host::GetBaseBoolSettingValue("UI", "StartFullscreen", false);
m_is_rendering_to_main = shouldRenderToMain();
m_is_surfaceless = false;
m_save_state_on_shutdown = false;
m_verbose_status = si.GetBoolValue("UI", "VerboseStatusBar", false);
m_pause_on_focus_loss = si.GetBoolValue("UI", "PauseOnFocusLoss", false);
}
void EmuThread::checkForSettingChanges()
void Host::LoadSettings(SettingsInterface& si, std::unique_lock<std::mutex>& lock)
{
CommonHost::LoadSettings(si, lock);
g_emu_thread->loadSettings(si, lock);
}
void EmuThread::checkForSettingChanges(const Pcsx2Config& old_config)
{
QMetaObject::invokeMethod(g_main_window, &MainWindow::checkForSettingChanges, Qt::QueuedConnection);
@ -605,12 +588,13 @@ void EmuThread::checkForSettingChanges()
}
}
const bool last_verbose_status = m_verbose_status;
updatePerformanceMetrics(true);
}
loadOurSettings();
if (m_verbose_status != last_verbose_status)
updatePerformanceMetrics(true);
void Host::CheckForSettingsChanges(const Pcsx2Config& old_config)
{
CommonHost::CheckForSettingsChanges(old_config);
g_emu_thread->checkForSettingChanges(old_config);
}
bool EmuThread::shouldRenderToMain() const
@ -855,6 +839,8 @@ void EmuThread::updateDisplay()
bool EmuThread::acquireHostDisplay(HostDisplay::RenderAPI api)
{
pxAssertRel(!g_host_display, "Host display does not exist on create");
m_is_rendering_to_main = shouldRenderToMain();
m_is_surfaceless = false;
g_host_display = HostDisplay::CreateDisplayForAPI(api);
if (!g_host_display)
@ -967,29 +953,35 @@ void Host::UpdateHostDisplay()
void Host::OnVMStarting()
{
CommonHost::OnVMStarting();
g_emu_thread->stopBackgroundControllerPollTimer();
emit g_emu_thread->onVMStarting();
}
void Host::OnVMStarted()
{
CommonHost::OnVMStarted();
emit g_emu_thread->onVMStarted();
}
void Host::OnVMDestroyed()
{
CommonHost::OnVMDestroyed();
emit g_emu_thread->onVMStopped();
g_emu_thread->startBackgroundControllerPollTimer();
}
void Host::OnVMPaused()
{
CommonHost::OnVMPaused();
g_emu_thread->startBackgroundControllerPollTimer();
emit g_emu_thread->onVMPaused();
}
void Host::OnVMResumed()
{
CommonHost::OnVMResumed();
// exit the event loop when we eventually return
g_emu_thread->getEventLoop()->quit();
g_emu_thread->stopBackgroundControllerPollTimer();
@ -1001,11 +993,10 @@ void Host::OnVMResumed()
emit g_emu_thread->onVMResumed();
}
void Host::OnGameChanged(const std::string& disc_path, const std::string& game_serial, const std::string& game_name,
u32 game_crc)
void Host::OnGameChanged(const std::string& disc_path, const std::string& game_serial, const std::string& game_name, u32 game_crc)
{
emit g_emu_thread->onGameChanged(QString::fromStdString(disc_path), QString::fromStdString(game_serial),
QString::fromStdString(game_name), game_crc);
CommonHost::OnGameChanged(disc_path, game_serial, game_name, game_crc);
emit g_emu_thread->onGameChanged(QString::fromStdString(disc_path), QString::fromStdString(game_serial), QString::fromStdString(game_name), game_crc);
}
void EmuThread::updatePerformanceMetrics(bool force)
@ -1117,9 +1108,10 @@ void Host::OnSaveStateSaved(const std::string_view& filename)
emit g_emu_thread->onSaveStateSaved(QtUtils::StringViewToQString(filename));
}
void Host::PumpMessagesOnCPUThread()
void Host::CPUThreadVSync()
{
g_emu_thread->getEventLoop()->processEvents(QEventLoop::AllEvents);
CommonHost::CPUThreadVSync();
}
void Host::RunOnCPUThread(std::function<void()> function, bool block /* = false */)
@ -1211,15 +1203,13 @@ bool QtHost::InitializeConfig()
SaveSettings();
}
CommonHost::SetBlockSystemConsole(QtHost::InNoGUIMode());
CommonHost::LoadStartupSettings();
Host::UpdateLogging(QtHost::InNoGUIMode());
return true;
}
void Host::SetDefaultUISettings(SettingsInterface& si)
{
Host::SetDefaultLoggingSettings(si);
si.SetBoolValue("UI", "InhibitScreensaver", true);
si.SetBoolValue("UI", "ConfirmShutdown", true);
si.SetBoolValue("UI", "StartPaused", false);
@ -1472,7 +1462,7 @@ void QtHost::HookSignals()
void QtHost::PrintCommandLineVersion()
{
Host::InitializeEarlyConsole();
CommonHost::InitializeEarlyConsole();
std::fprintf(stderr, "%s\n", (GetAppNameAndVersion() + GetAppConfigSuffix()).toUtf8().constData());
std::fprintf(stderr, "https://pcsx2.net/\n");
std::fprintf(stderr, "\n");
@ -1592,7 +1582,7 @@ bool QtHost::ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMB
}
else if (CHECK_ARG("-earlyconsolelog"))
{
Host::InitializeEarlyConsole();
CommonHost::InitializeEarlyConsole();
continue;
}
else if (CHECK_ARG("-bigpicture"))
@ -1607,7 +1597,7 @@ bool QtHost::ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMB
}
else if (argv[i][0] == '-')
{
Host::InitializeEarlyConsole();
CommonHost::InitializeEarlyConsole();
std::fprintf(stderr, "Unknown parameter: '%s'", argv[i]);
return false;
}
@ -1626,7 +1616,7 @@ bool QtHost::ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMB
// or disc, we don't want to actually start.
if (autoboot && !autoboot->source_type.has_value() && autoboot->filename.empty() && autoboot->elf_override.empty())
{
Host::InitializeEarlyConsole();
CommonHost::InitializeEarlyConsole();
Console.Warning("Skipping autoboot due to no boot parameters.");
autoboot.reset();
}

View File

@ -80,6 +80,8 @@ public:
public Q_SLOTS:
bool confirmMessage(const QString& title, const QString& message);
void loadSettings(SettingsInterface& si, std::unique_lock<std::mutex>& lock);
void checkForSettingChanges(const Pcsx2Config& old_config);
void startFullscreenUI(bool fullscreen);
void stopFullscreenUI();
void startVM(std::shared_ptr<VMBootParameters> boot_params);
@ -161,14 +163,11 @@ private:
void destroyVM();
void executeVM();
void checkForSettingChanges();
bool shouldRenderToMain() const;
void createBackgroundControllerPollTimer();
void destroyBackgroundControllerPollTimer();
void connectSignals();
void loadOurSettings();
void loadOurInitialSettings();
private Q_SLOTS:
void stopInThread();

View File

@ -22,7 +22,7 @@
#include "Settings/HotkeySettingsWidget.h"
#include "pcsx2/Frontend/CommonHost.h"
#include "pcsx2/Frontend/INISettingsInterface.h"
#include "pcsx2/INISettingsInterface.h"
#include "pcsx2/PAD/Host/PAD.h"
#include "pcsx2/Sio.h"
#include "pcsx2/VMManager.h"

View File

@ -24,13 +24,13 @@
#include "common/StringUtil.h"
#include "pcsx2/HostSettings.h"
#include "pcsx2/INISettingsInterface.h"
#include "DEV9SettingsWidget.h"
#include "QtHost.h"
#include "QtUtils.h"
#include "SettingWidgetBinder.h"
#include "SettingsDialog.h"
#include "Frontend/INISettingsInterface.h"
#include "HddCreateQt.h"

View File

@ -19,9 +19,9 @@
#include "common/Path.h"
#include "common/StringUtil.h"
#include "pcsx2/HostSettings.h"
#include "pcsx2/Frontend/GameList.h"
#include "pcsx2/Frontend/INISettingsInterface.h"
#include "pcsx2/HostSettings.h"
#include "pcsx2/INISettingsInterface.h"
#include "MainWindow.h"
#include "QtHost.h"

View File

@ -1064,16 +1064,17 @@ endif()
if(PCSX2_CORE)
list(APPEND pcsx2FrontendSources
Frontend/CommonHost.cpp
Frontend/CommonHotkeys.cpp
Frontend/FullscreenUI.cpp
Frontend/GameList.cpp
Frontend/HostSettings.cpp
Frontend/ImGuiFullscreen.cpp
Frontend/INISettingsInterface.cpp
Frontend/InputManager.cpp
Frontend/InputSource.cpp
Frontend/LayeredSettingsInterface.cpp
Frontend/LogSink.cpp
GSDumpReplayer.cpp
INISettingsInterface.cpp
VMManager.cpp
)
list(APPEND pcsx2FrontendHeaders
@ -1081,13 +1082,13 @@ if(PCSX2_CORE)
Frontend/FullscreenUI.h
Frontend/GameList.h
Frontend/ImGuiFullscreen.h
Frontend/INISettingsInterface.h
Frontend/InputManager.h
Frontend/InputSource.h
Frontend/LayeredSettingsInterface.h
Frontend/LogSink.h
GSDumpReplayer.h
HostSettings.h
INISettingsInterface.h
VMManager.h)
endif()

View File

@ -18,14 +18,21 @@
#include "common/CrashHandler.h"
#include "common/FileSystem.h"
#include "common/Path.h"
#include "common/Threading.h"
#include "Frontend/CommonHost.h"
#include "Frontend/FullscreenUI.h"
#include "Frontend/GameList.h"
#include "Frontend/LayeredSettingsInterface.h"
#include "Frontend/InputManager.h"
#include "Frontend/LogSink.h"
#include "GS.h"
#include "GS/Renderers/HW/GSTextureReplacements.h"
#include "Host.h"
#include "HostSettings.h"
#include "IconsFontAwesome5.h"
#include "MemoryCardFile.h"
#include "PAD/Host/PAD.h"
#include "PerformanceMetrics.h"
#include "Sio.h"
#include "VMManager.h"
@ -175,6 +182,7 @@ void CommonHost::LoadStartupSettings()
SettingsInterface* bsi = Host::Internal::GetBaseSettingsLayer();
EmuFolders::LoadConfig(*bsi);
EmuFolders::EnsureFoldersExist();
UpdateLogging(*bsi);
}
void CommonHost::SetDefaultSettings(SettingsInterface& si, bool folders, bool core, bool controllers, bool hotkeys, bool ui)
@ -199,5 +207,106 @@ void CommonHost::SetDefaultSettings(SettingsInterface& si, bool folders, bool co
void CommonHost::SetCommonDefaultSettings(SettingsInterface& si)
{
// Nothing here yet.
SetDefaultLoggingSettings(si);
}
void CommonHost::CPUThreadInitialize()
{
Threading::SetNameOfCurrentThread("CPU Thread");
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle::GetForCallingThread());
// neither of these should ever fail.
if (!VMManager::Internal::InitializeGlobals() || !VMManager::Internal::InitializeMemory())
pxFailRel("Failed to allocate memory map");
// We want settings loaded so we choose the correct renderer for big picture mode.
// This also sorts out input sources.
VMManager::LoadSettings();
}
void CommonHost::CPUThreadShutdown()
{
InputManager::CloseSources();
VMManager::WaitForSaveStateFlush();
VMManager::Internal::ReleaseMemory();
VMManager::Internal::ReleaseGlobals();
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle());
}
void CommonHost::LoadSettings(SettingsInterface& si, std::unique_lock<std::mutex>& lock)
{
SettingsInterface* binding_si = Host::GetSettingsInterfaceForBindings();
InputManager::ReloadSources(si, lock);
InputManager::ReloadBindings(si, *binding_si);
UpdateLogging(si);
}
void CommonHost::CheckForSettingsChanges(const Pcsx2Config& old_config)
{
// Nothing yet.
}
void CommonHost::OnVMStarting()
{
CommonHost::Internal::ResetVMHotkeyState();
}
void CommonHost::OnVMStarted()
{
FullscreenUI::OnVMStarted();
}
void CommonHost::OnVMDestroyed()
{
FullscreenUI::OnVMDestroyed();
}
void CommonHost::OnVMPaused()
{
InputManager::PauseVibration();
FullscreenUI::OnVMPaused();
}
void CommonHost::OnVMResumed()
{
FullscreenUI::OnVMResumed();
}
void CommonHost::OnGameChanged(const std::string& disc_path, const std::string& game_serial, const std::string& game_name, u32 game_crc)
{
if (FullscreenUI::IsInitialized())
{
GetMTGS().RunOnGSThread([disc_path, game_serial, game_name, game_crc]() {
FullscreenUI::OnRunningGameChanged(std::move(disc_path), std::move(game_serial), std::move(game_name), game_crc);
});
}
}
void CommonHost::CPUThreadVSync()
{
InputManager::PollSources();
}
bool Host::GetSerialAndCRCForFilename(const char* filename, std::string* serial, u32* crc)
{
{
auto lock = GameList::GetLock();
if (const GameList::Entry* entry = GameList::GetEntryForPath(filename); entry)
{
*serial = entry->serial;
*crc = entry->crc;
return true;
}
}
// Just scan it.. hopefully it'll come back okay.
GameList::Entry temp_entry;
if (GameList::PopulateEntryFromPath(filename, &temp_entry))
{
*serial = std::move(temp_entry.serial);
*crc = temp_entry.crc;
return true;
}
return false;
}

View File

@ -19,6 +19,8 @@
#include <string>
#include <mutex>
#include "Config.h"
class SettingsInterface;
namespace Host
@ -40,4 +42,43 @@ namespace CommonHost
/// Sets default settings for the specified categories.
void SetDefaultSettings(SettingsInterface& si, bool folders, bool core, bool controllers, bool hotkeys, bool ui);
/// Initializes common host state, called on the CPU thread.
void CPUThreadInitialize();
/// Cleans up common host state, called on the CPU thread.
void CPUThreadShutdown();
/// Loads common host settings (including input bindings).
void LoadSettings(SettingsInterface& si, std::unique_lock<std::mutex>& lock);
/// Called after settings are updated.
void CheckForSettingsChanges(const Pcsx2Config& old_config);
/// Called when the VM is starting initialization, but has not been completed yet.
void OnVMStarting();
/// Called when the VM is created.
void OnVMStarted();
/// Called when the VM is shut down or destroyed.
void OnVMDestroyed();
/// Called when the VM is paused.
void OnVMPaused();
/// Called when the VM is resumed after being paused.
void OnVMResumed();
/// Called when the running executable changes.
void OnGameChanged(const std::string& disc_path, const std::string& game_serial, const std::string& game_name, u32 game_crc);
/// Provided by the host; called once per frame at guest vsync.
void CPUThreadVSync();
namespace Internal
{
/// Resets any state for hotkey-related VMs, called on VM startup.
void ResetVMHotkeyState();
} // namespace Internal
} // namespace CommonHost

View File

@ -0,0 +1,240 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "common/Assertions.h"
#include "common/FileSystem.h"
#include "common/Path.h"
#include "Frontend/CommonHost.h"
#include "Frontend/FullscreenUI.h"
#include "Frontend/InputManager.h"
#include "GS.h"
#include "Host.h"
#include "IconsFontAwesome5.h"
#include "Recording/InputRecordingControls.h"
#include "VMManager.h"
static s32 s_current_save_slot = 1;
static std::optional<LimiterModeType> s_limiter_mode_prior_to_hold_interaction;
void CommonHost::Internal::ResetVMHotkeyState()
{
s_current_save_slot = 1;
s_limiter_mode_prior_to_hold_interaction.reset();
}
static void HotkeyAdjustTargetSpeed(double delta)
{
EmuConfig.Framerate.NominalScalar = EmuConfig.GS.LimitScalar + delta;
VMManager::SetLimiterMode(LimiterModeType::Nominal);
gsUpdateFrequency(EmuConfig);
GetMTGS().SetVSync(EmuConfig.GetEffectiveVsyncMode());
Host::AddIconOSDMessage("SpeedChanged", ICON_FA_CLOCK,
fmt::format("Target speed set to {:.0f}%.", std::round(EmuConfig.Framerate.NominalScalar * 100.0)), 5.0f);
}
static constexpr s32 CYCLE_SAVE_STATE_SLOTS = 10;
static void HotkeyCycleSaveSlot(s32 delta)
{
// 1..10
s_current_save_slot = ((s_current_save_slot - 1) + delta);
if (s_current_save_slot < 0)
s_current_save_slot = CYCLE_SAVE_STATE_SLOTS;
else
s_current_save_slot = (s_current_save_slot % CYCLE_SAVE_STATE_SLOTS) + 1;
const u32 crc = VMManager::GetGameCRC();
const std::string serial(VMManager::GetGameSerial());
const std::string filename(VMManager::GetSaveStateFileName(serial.c_str(), crc, s_current_save_slot));
FILESYSTEM_STAT_DATA sd;
if (!filename.empty() && FileSystem::StatFile(filename.c_str(), &sd))
{
char date_buf[128] = {};
#ifdef _WIN32
ctime_s(date_buf, std::size(date_buf), &sd.ModificationTime);
#else
ctime_r(&sd.ModificationTime, date_buf);
#endif
// remove terminating \n
size_t len = std::strlen(date_buf);
if (len > 0 && date_buf[len - 1] == '\n')
date_buf[len - 1] = 0;
Host::AddIconOSDMessage(
"CycleSaveSlot", ICON_FA_SEARCH, fmt::format("Save slot {} selected (last save: {}).", s_current_save_slot, date_buf), 5.0f);
}
else
{
Host::AddIconOSDMessage(
"CycleSaveSlot", ICON_FA_SEARCH, fmt::format("Save slot {} selected (no save yet).", s_current_save_slot), 5.0f);
}
}
static void HotkeyLoadStateSlot(s32 slot)
{
const u32 crc = VMManager::GetGameCRC();
if (crc == 0)
{
Host::AddIconOSDMessage(
"LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE, "Cannot load state from a slot without a game running.", 10.0f);
return;
}
const std::string serial(VMManager::GetGameSerial());
if (!VMManager::HasSaveStateInSlot(serial.c_str(), crc, slot))
{
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE, fmt::format("No save state found in slot {}.", slot));
return;
}
VMManager::LoadStateFromSlot(slot);
}
static void HotkeySaveStateSlot(s32 slot)
{
if (VMManager::GetGameCRC() == 0)
{
Host::AddIconOSDMessage(
"SaveStateToSlot", ICON_FA_EXCLAMATION_TRIANGLE, "Cannot save state to a slot without a game running.", 10.0f);
return;
}
VMManager::SaveStateToSlot(slot);
}
BEGIN_HOTKEY_LIST(g_common_hotkeys)
DEFINE_HOTKEY("OpenPauseMenu", "System", "Open Pause Menu", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
FullscreenUI::OpenPauseMenu();
})
DEFINE_HOTKEY("TogglePause", "System", "Toggle Pause", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
VMManager::SetPaused(VMManager::GetState() != VMState::Paused);
})
DEFINE_HOTKEY("ToggleFullscreen", "System", "Toggle Fullscreen", [](s32 pressed) {
if (!pressed)
Host::SetFullscreen(!Host::IsFullscreen());
})
DEFINE_HOTKEY("ToggleFrameLimit", "System", "Toggle Frame Limit", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
{
VMManager::SetLimiterMode(
(EmuConfig.LimiterMode != LimiterModeType::Unlimited) ? LimiterModeType::Unlimited : LimiterModeType::Nominal);
}
})
DEFINE_HOTKEY("ToggleTurbo", "System", "Toggle Turbo", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
{
VMManager::SetLimiterMode((EmuConfig.LimiterMode != LimiterModeType::Turbo) ? LimiterModeType::Turbo : LimiterModeType::Nominal);
}
})
DEFINE_HOTKEY("ToggleSlowMotion", "System", "Toggle Slow Motion", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
{
VMManager::SetLimiterMode((EmuConfig.LimiterMode != LimiterModeType::Slomo) ? LimiterModeType::Slomo : LimiterModeType::Nominal);
}
})
DEFINE_HOTKEY("HoldTurbo", "System", "Turbo (Hold)", [](s32 pressed) {
if (!VMManager::HasValidVM())
return;
if (pressed > 0 && !s_limiter_mode_prior_to_hold_interaction.has_value())
{
s_limiter_mode_prior_to_hold_interaction = VMManager::GetLimiterMode();
VMManager::SetLimiterMode((s_limiter_mode_prior_to_hold_interaction.value() != LimiterModeType::Turbo) ? LimiterModeType::Turbo :
LimiterModeType::Nominal);
}
else if (pressed >= 0 && s_limiter_mode_prior_to_hold_interaction.has_value())
{
VMManager::SetLimiterMode(s_limiter_mode_prior_to_hold_interaction.value());
s_limiter_mode_prior_to_hold_interaction.reset();
}
})
DEFINE_HOTKEY("IncreaseSpeed", "System", "Increase Target Speed", [](s32 pressed) {
if (!pressed)
HotkeyAdjustTargetSpeed(0.1);
})
DEFINE_HOTKEY("DecreaseSpeed", "System", "Decrease Target Speed", [](s32 pressed) {
if (!pressed)
HotkeyAdjustTargetSpeed(-0.1);
})
DEFINE_HOTKEY("FrameAdvance", "System", "Frame Advance", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
VMManager::FrameAdvance(1);
})
DEFINE_HOTKEY("ShutdownVM", "System", "Shut Down Virtual Machine", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
Host::RequestVMShutdown(true, true, EmuConfig.SaveStateOnShutdown);
})
DEFINE_HOTKEY("ResetVM", "System", "Reset Virtual Machine", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
VMManager::Reset();
})
DEFINE_HOTKEY("InputRecToggleMode", "System", "Toggle Input Recording Mode", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
g_InputRecordingControls.RecordModeToggle();
})
DEFINE_HOTKEY("PreviousSaveStateSlot", "Save States", "Select Previous Save Slot", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
HotkeyCycleSaveSlot(-1);
})
DEFINE_HOTKEY("NextSaveStateSlot", "Save States", "Select Next Save Slot", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
HotkeyCycleSaveSlot(1);
})
DEFINE_HOTKEY("SaveStateToSlot", "Save States", "Save State To Selected Slot", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
VMManager::SaveStateToSlot(s_current_save_slot);
})
DEFINE_HOTKEY("LoadStateFromSlot", "Save States", "Load State From Selected Slot", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
HotkeyLoadStateSlot(s_current_save_slot);
})
#define DEFINE_HOTKEY_SAVESTATE_X(slotnum) \
DEFINE_HOTKEY("SaveStateToSlot" #slotnum, "Save States", "Save State To Slot " #slotnum, [](s32 pressed) { \
if (!pressed) \
HotkeySaveStateSlot(slotnum); \
})
#define DEFINE_HOTKEY_LOADSTATE_X(slotnum) \
DEFINE_HOTKEY("LoadStateFromSlot" #slotnum, "Save States", "Load State From Slot " #slotnum, [](s32 pressed) { \
if (!pressed) \
HotkeyLoadStateSlot(slotnum); \
})
DEFINE_HOTKEY_SAVESTATE_X(1)
DEFINE_HOTKEY_LOADSTATE_X(1)
DEFINE_HOTKEY_SAVESTATE_X(2)
DEFINE_HOTKEY_LOADSTATE_X(2)
DEFINE_HOTKEY_SAVESTATE_X(3)
DEFINE_HOTKEY_LOADSTATE_X(3)
DEFINE_HOTKEY_SAVESTATE_X(4)
DEFINE_HOTKEY_LOADSTATE_X(4)
DEFINE_HOTKEY_SAVESTATE_X(5)
DEFINE_HOTKEY_LOADSTATE_X(5)
DEFINE_HOTKEY_SAVESTATE_X(6)
DEFINE_HOTKEY_LOADSTATE_X(6)
DEFINE_HOTKEY_SAVESTATE_X(7)
DEFINE_HOTKEY_LOADSTATE_X(7)
DEFINE_HOTKEY_SAVESTATE_X(8)
DEFINE_HOTKEY_LOADSTATE_X(8)
DEFINE_HOTKEY_SAVESTATE_X(9)
DEFINE_HOTKEY_LOADSTATE_X(9)
DEFINE_HOTKEY_SAVESTATE_X(10)
DEFINE_HOTKEY_LOADSTATE_X(10)
#undef DEFINE_HOTKEY_SAVESTATE_X
#undef DEFINE_HOTKEY_LOADSTATE_X
END_HOTKEY_LIST()

View File

@ -20,7 +20,6 @@
#include "Frontend/FullscreenUI.h"
#include "Frontend/ImGuiManager.h"
#include "Frontend/ImGuiFullscreen.h"
#include "Frontend/INISettingsInterface.h"
#include "Frontend/InputManager.h"
#include "Frontend/GameList.h"
#include "IconsFontAwesome5.h"
@ -40,6 +39,7 @@
#include "Host.h"
#include "HostDisplay.h"
#include "HostSettings.h"
#include "INISettingsInterface.h"
#include "MemoryCardFile.h"
#include "PAD/Host/PAD.h"
#include "ps2/BiosTools.h"
@ -855,7 +855,7 @@ void FullscreenUI::DoChangeDiscFromFile()
auto callback = [](const std::string& path) {
if (!path.empty())
{
if (!GameList::IsScannableFilename(path))
if (!VMManager::IsDiscFileName(path))
{
ShowToast({}, fmt::format("{} is not a valid disc image.", FileSystem::GetDisplayNameFromPath(path)));
}

View File

@ -46,6 +46,8 @@ namespace GameList
{
using CacheMap = std::unordered_map<std::string, GameList::Entry>;
static bool IsScannableFilename(const std::string_view& path);
static Entry* GetMutableEntryForPath(const char* path);
static bool GetElfListEntry(const std::string& path, GameList::Entry* entry);
@ -119,15 +121,7 @@ const char* GameList::EntryCompatibilityRatingToString(CompatibilityRating ratin
bool GameList::IsScannableFilename(const std::string_view& path)
{
static const char* extensions[] = {".iso", ".mdf", ".nrg", ".bin", ".img", ".gz", ".cso", ".chd", ".elf", ".irx"};
for (const char* test_extension : extensions)
{
if (StringUtil::EndsWithNoCase(path, test_extension))
return true;
}
return false;
return VMManager::IsDiscFileName(path) || VMManager::IsElfFileName(path);
}
void GameList::FillBootParametersForEntry(VMBootParameters* params, const Entry* entry)

View File

@ -100,8 +100,6 @@ namespace GameList
const char* RegionToString(Region region);
const char* EntryCompatibilityRatingToString(CompatibilityRating rating);
bool IsScannableFilename(const std::string_view& path);
/// Fills in boot parameters (iso or elf) based on the game list entry.
void FillBootParametersForEntry(VMBootParameters* params, const Entry* entry);

View File

@ -134,7 +134,7 @@ static std::array<std::unique_ptr<InputSource>, static_cast<u32>(InputSourceType
// ------------------------------------------------------------------------
// Hotkeys
// ------------------------------------------------------------------------
static const HotkeyInfo* const s_hotkey_list[] = {g_host_hotkeys, g_vm_manager_hotkeys, g_gs_hotkeys};
static const HotkeyInfo* const s_hotkey_list[] = {g_common_hotkeys, g_gs_hotkeys, g_host_hotkeys};
// ------------------------------------------------------------------------
// Tracking host mouse movement and turning into relative events

View File

@ -131,7 +131,7 @@ struct HotkeyInfo
} \
;
DECLARE_HOTKEY_LIST(g_vm_manager_hotkeys);
DECLARE_HOTKEY_LIST(g_common_hotkeys);
DECLARE_HOTKEY_LIST(g_gs_hotkeys);
DECLARE_HOTKEY_LIST(g_host_hotkeys);

View File

@ -66,6 +66,7 @@ static const char s_console_colors[][ConsoleColors_Count] = {
};
#undef CC
static bool s_block_system_console = false;
static Common::Timer::Value s_log_start_timestamp = Common::Timer::GetCurrentValue();
static bool s_log_timestamps = false;
static std::mutex s_log_mutex;
@ -364,31 +365,36 @@ static void UpdateLoggingSinks(bool system_console, bool file_log)
Console_SetActiveHandler(ConsoleWriter_Null);
}
void Host::InitializeEarlyConsole()
void CommonHost::SetBlockSystemConsole(bool block)
{
s_block_system_console = block;
}
void CommonHost::InitializeEarlyConsole()
{
UpdateLoggingSinks(true, false);
}
void Host::UpdateLogging(bool disable_system_console)
void CommonHost::UpdateLogging(SettingsInterface& si)
{
const bool system_console_enabled = !disable_system_console && Host::GetBaseBoolSettingValue("Logging", "EnableSystemConsole", false);
const bool file_logging_enabled = Host::GetBaseBoolSettingValue("Logging", "EnableFileLogging", false);
const bool system_console_enabled = !s_block_system_console && si.GetBoolValue("Logging", "EnableSystemConsole", false);
const bool file_logging_enabled = si.GetBoolValue("Logging", "EnableFileLogging", false);
s_log_timestamps = Host::GetBaseBoolSettingValue("Logging", "EnableTimestamps", true);
s_log_timestamps = si.GetBoolValue("Logging", "EnableTimestamps", true);
const bool any_logging_sinks = system_console_enabled || file_logging_enabled;
DevConWriterEnabled = any_logging_sinks && (IsDevBuild || Host::GetBaseBoolSettingValue("Logging", "EnableVerbose", false));
SysConsole.eeConsole.Enabled = any_logging_sinks && Host::GetBaseBoolSettingValue("Logging", "EnableEEConsole", false);
SysConsole.iopConsole.Enabled = any_logging_sinks && Host::GetBaseBoolSettingValue("Logging", "EnableIOPConsole", false);
DevConWriterEnabled = any_logging_sinks && (IsDevBuild || si.GetBoolValue("Logging", "EnableVerbose", false));
SysConsole.eeConsole.Enabled = any_logging_sinks && si.GetBoolValue("Logging", "EnableEEConsole", false);
SysConsole.iopConsole.Enabled = any_logging_sinks && si.GetBoolValue("Logging", "EnableIOPConsole", false);
// Input Recording Logs
SysConsole.recordingConsole.Enabled = any_logging_sinks && Host::GetBaseBoolSettingValue("Logging", "EnableInputRecordingLogs", true);
SysConsole.controlInfo.Enabled = any_logging_sinks && Host::GetBaseBoolSettingValue("Logging", "EnableControllerLogs", false);
SysConsole.recordingConsole.Enabled = any_logging_sinks && si.GetBoolValue("Logging", "EnableInputRecordingLogs", true);
SysConsole.controlInfo.Enabled = any_logging_sinks && si.GetBoolValue("Logging", "EnableControllerLogs", false);
UpdateLoggingSinks(system_console_enabled, file_logging_enabled);
}
void Host::SetDefaultLoggingSettings(SettingsInterface& si)
void CommonHost::SetDefaultLoggingSettings(SettingsInterface& si)
{
si.SetBoolValue("Logging", "EnableSystemConsole", false);
si.SetBoolValue("Logging", "EnableFileLogging", false);

View File

@ -17,10 +17,13 @@
class SettingsInterface;
namespace Host
namespace CommonHost
{
/// Prevents the system console from being displayed.
void SetBlockSystemConsole(bool block);
/// Updates the Console handler based on the current configuration.
void UpdateLogging(bool disable_system_console);
void UpdateLogging(SettingsInterface& si);
/// Initializes early console logging (for printing command line arguments).
void InitializeEarlyConsole();

View File

@ -39,6 +39,7 @@
#include "GSDumpReplayer.h"
#include "HostDisplay.h"
#include "HostSettings.h"
#include "INISettingsInterface.h"
#include "IopBios.h"
#include "MTVU.h"
#include "MemoryCardFile.h"
@ -56,10 +57,6 @@
#include "DebugTools/MIPSAnalyst.h"
#include "DebugTools/SymbolMap.h"
#include "Frontend/FullscreenUI.h"
#include "Frontend/INISettingsInterface.h"
#include "Frontend/InputManager.h"
#include "Frontend/GameList.h"
#include "IconsFontAwesome5.h"
#include "common/emitter/tools.h"
@ -135,10 +132,8 @@ static std::vector<u8> s_no_interlacing_cheats_data;
static bool s_no_interlacing_cheats_loaded = false;
static s32 s_active_widescreen_patches = 0;
static u32 s_active_no_interlacing_patches = 0;
static s32 s_current_save_slot = 1;
static u32 s_frame_advance_count = 0;
static u32 s_mxcsr_saved;
static std::optional<LimiterModeType> s_limiter_mode_prior_to_hold_interaction;
static bool s_gs_open_on_initialize = false;
bool VMManager::PerformEarlyHardwareChecks(const char** error)
@ -193,7 +188,6 @@ void VMManager::SetState(VMState state)
if (THREAD_VU1)
vu1Thread.WaitVU();
GetMTGS().WaitGS(false);
InputManager::PauseVibration();
}
else
{
@ -203,15 +197,9 @@ void VMManager::SetState(VMState state)
SPU2SetOutputPaused(state == VMState::Paused);
if (state == VMState::Paused)
{
Host::OnVMPaused();
FullscreenUI::OnVMPaused();
}
else
{
Host::OnVMResumed();
FullscreenUI::OnVMResumed();
}
}
}
@ -319,12 +307,10 @@ void VMManager::LoadSettings()
{
std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
SettingsInterface* si = Host::GetSettingsInterface();
SettingsInterface* binding_si = Host::GetSettingsInterfaceForBindings();
SettingsLoadWrapper slw(*si);
EmuConfig.LoadSave(slw);
PAD::LoadConfig(*binding_si);
InputManager::ReloadSources(*si, lock);
InputManager::ReloadBindings(*si, *binding_si);
PAD::LoadConfig(*si);
Host::LoadSettings(*si, lock);
// Remove any user-specified hacks in the config (we don't want stale/conflicting values when it's globally disabled).
EmuConfig.GS.MaskUserHacks();
@ -703,12 +689,6 @@ void VMManager::UpdateRunningGame(bool resetting, bool game_starting)
GetMTGS().SendGameCRC(new_crc);
Host::OnGameChanged(s_disc_path, s_game_serial, s_game_name, s_game_crc);
if (FullscreenUI::IsInitialized())
{
GetMTGS().RunOnGSThread([disc_path = s_disc_path, game_serial = s_game_serial, game_name = s_game_name, game_crc = s_game_crc]() {
FullscreenUI::OnRunningGameChanged(std::move(disc_path), std::move(game_serial), std::move(game_name), game_crc);
});
}
#if 0
// TODO: Enable this when the debugger is added to Qt, and it's active. Otherwise, this is just a waste of time.
@ -992,7 +972,6 @@ bool VMManager::Initialize(VMBootParameters boot_params)
Console.WriteLn("VM subsystems initialized in %.2f ms", init_timer.GetTimeMilliseconds());
s_state.store(VMState::Paused, std::memory_order_release);
Host::OnVMStarted();
FullscreenUI::OnVMStarted();
UpdateRunningGame(true, false);
@ -1055,7 +1034,6 @@ void VMManager::Shutdown(bool save_resume_state)
s_active_game_fixes = 0;
s_active_widescreen_patches = 0;
s_active_no_interlacing_patches = 0;
s_limiter_mode_prior_to_hold_interaction.reset();
UpdateGameSettingsLayer();
@ -1094,7 +1072,6 @@ void VMManager::Shutdown(bool save_resume_state)
s_state.store(VMState::Shutdown, std::memory_order_release);
Host::OnVMDestroyed();
FullscreenUI::OnVMDestroyed();
}
void VMManager::Reset()
@ -1104,7 +1081,6 @@ void VMManager::Reset()
s_active_game_fixes = 0;
s_active_widescreen_patches = 0;
s_active_no_interlacing_patches = 0;
s_limiter_mode_prior_to_hold_interaction.reset();
SysClearExecutionCache();
memBindConditionalHandlers();
@ -1138,22 +1114,10 @@ std::string VMManager::GetSaveStateFileName(const char* filename, s32 slot)
pxAssertRel(!HasValidVM(), "Should not have a VM when calling the non-gamelist GetSaveStateFileName()");
std::string ret;
// try the game list first, but this won't work if we're in batch mode
auto lock = GameList::GetLock();
if (const GameList::Entry* entry = GameList::GetEntryForPath(filename); entry)
{
ret = GetSaveStateFileName(entry->serial.c_str(), entry->crc, slot);
}
else
{
// just scan it.. hopefully it'll come back okay
GameList::Entry temp_entry;
if (GameList::PopulateEntryFromPath(filename, &temp_entry))
{
ret = GetSaveStateFileName(temp_entry.serial.c_str(), temp_entry.crc, slot);
}
}
std::string serial;
u32 crc;
if (Host::GetSerialAndCRCForFilename(filename, &serial, &crc))
ret = GetSaveStateFileName(serial.c_str(), crc, slot);
return ret;
}
@ -1409,9 +1373,22 @@ bool VMManager::IsSaveStateFileName(const std::string_view& path)
return StringUtil::EndsWithNoCase(path, ".p2s");
}
bool VMManager::IsDiscFileName(const std::string_view& path)
{
static const char* extensions[] = {".iso", ".bin", ".img", ".gz", ".cso", ".chd"};
for (const char* test_extension : extensions)
{
if (StringUtil::EndsWithNoCase(path, test_extension))
return true;
}
return false;
}
bool VMManager::IsLoadableFileName(const std::string_view& path)
{
return IsElfFileName(path) || IsGSDumpFileName(path) || IsBlockDumpFileName(path) || GameList::IsScannableFilename(path);
return IsDiscFileName(path) || IsElfFileName(path) || IsGSDumpFileName(path) || IsBlockDumpFileName(path);
}
void VMManager::Execute()
@ -1482,8 +1459,7 @@ void VMManager::Internal::VSyncOnCPUThread()
}
}
Host::PumpMessagesOnCPUThread();
InputManager::PollSources();
Host::CPUThreadVSync();
}
void VMManager::CheckForCPUConfigChanges(const Pcsx2Config& old_config)
@ -1681,6 +1657,8 @@ void VMManager::CheckForConfigChanges(const Pcsx2Config& old_config)
// and we don't update its config when we start the VM.
if (HasValidVM() || GetMTGS().IsOpen())
CheckForGSConfigChanges(old_config);
Host::CheckForSettingsChanges(old_config);
}
void VMManager::ApplySettings()
@ -1808,204 +1786,6 @@ void VMManager::WarnAboutUnsafeSettings()
}
}
static void HotkeyAdjustTargetSpeed(double delta)
{
EmuConfig.Framerate.NominalScalar = EmuConfig.GS.LimitScalar + delta;
VMManager::SetLimiterMode(LimiterModeType::Nominal);
gsUpdateFrequency(EmuConfig);
GetMTGS().SetVSync(EmuConfig.GetEffectiveVsyncMode());
Host::AddIconOSDMessage("SpeedChanged", ICON_FA_CLOCK, fmt::format("Target speed set to {:.0f}%.", std::round(EmuConfig.Framerate.NominalScalar * 100.0)), 5.0f);
}
static constexpr s32 CYCLE_SAVE_STATE_SLOTS = 10;
static void HotkeyCycleSaveSlot(s32 delta)
{
// 1..10
s_current_save_slot = ((s_current_save_slot - 1) + delta);
if (s_current_save_slot < 0)
s_current_save_slot = CYCLE_SAVE_STATE_SLOTS;
else
s_current_save_slot = (s_current_save_slot % CYCLE_SAVE_STATE_SLOTS) + 1;
const std::string filename(VMManager::GetSaveStateFileName(s_game_serial.c_str(), s_game_crc, s_current_save_slot));
FILESYSTEM_STAT_DATA sd;
if (!filename.empty() && FileSystem::StatFile(filename.c_str(), &sd))
{
char date_buf[128] = {};
#ifdef _WIN32
ctime_s(date_buf, std::size(date_buf), &sd.ModificationTime);
#else
ctime_r(&sd.ModificationTime, date_buf);
#endif
// remove terminating \n
size_t len = std::strlen(date_buf);
if (len > 0 && date_buf[len - 1] == '\n')
date_buf[len - 1] = 0;
Host::AddIconOSDMessage("CycleSaveSlot", ICON_FA_SEARCH, fmt::format("Save slot {} selected (last save: {}).", s_current_save_slot, date_buf), 5.0f);
}
else
{
Host::AddIconOSDMessage("CycleSaveSlot", ICON_FA_SEARCH, fmt::format("Save slot {} selected (no save yet).", s_current_save_slot), 5.0f);
}
}
static void HotkeyLoadStateSlot(s32 slot)
{
if (s_game_crc == 0)
{
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE, "Cannot load state from a slot without a game running.", 10.0f);
return;
}
if (!VMManager::HasSaveStateInSlot(s_game_serial.c_str(), s_game_crc, slot))
{
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE, fmt::format("No save state found in slot {}.", slot));
return;
}
VMManager::LoadStateFromSlot(slot);
}
static void HotkeySaveStateSlot(s32 slot)
{
if (s_game_crc == 0)
{
Host::AddIconOSDMessage("SaveStateToSlot", ICON_FA_EXCLAMATION_TRIANGLE, "Cannot save state to a slot without a game running.", 10.0f);
return;
}
VMManager::SaveStateToSlot(slot);
}
BEGIN_HOTKEY_LIST(g_vm_manager_hotkeys)
DEFINE_HOTKEY("OpenPauseMenu", "System", "Open Pause Menu", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
FullscreenUI::OpenPauseMenu();
})
DEFINE_HOTKEY("TogglePause", "System", "Toggle Pause", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
VMManager::SetPaused(VMManager::GetState() != VMState::Paused);
})
DEFINE_HOTKEY("ToggleFullscreen", "System", "Toggle Fullscreen", [](s32 pressed) {
if (!pressed)
Host::SetFullscreen(!Host::IsFullscreen());
})
DEFINE_HOTKEY("ToggleFrameLimit", "System", "Toggle Frame Limit", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
{
VMManager::SetLimiterMode((EmuConfig.LimiterMode != LimiterModeType::Unlimited) ?
LimiterModeType::Unlimited :
LimiterModeType::Nominal);
}
})
DEFINE_HOTKEY("ToggleTurbo", "System", "Toggle Turbo", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
{
VMManager::SetLimiterMode((EmuConfig.LimiterMode != LimiterModeType::Turbo) ?
LimiterModeType::Turbo :
LimiterModeType::Nominal);
}
})
DEFINE_HOTKEY("ToggleSlowMotion", "System", "Toggle Slow Motion", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
{
VMManager::SetLimiterMode((EmuConfig.LimiterMode != LimiterModeType::Slomo) ?
LimiterModeType::Slomo :
LimiterModeType::Nominal);
}
})
DEFINE_HOTKEY("HoldTurbo", "System", "Turbo (Hold)", [](s32 pressed) {
if (!VMManager::HasValidVM())
return;
if (pressed > 0 && !s_limiter_mode_prior_to_hold_interaction.has_value())
{
s_limiter_mode_prior_to_hold_interaction = VMManager::GetLimiterMode();
VMManager::SetLimiterMode((s_limiter_mode_prior_to_hold_interaction.value() != LimiterModeType::Turbo) ?
LimiterModeType::Turbo :
LimiterModeType::Nominal);
}
else if (pressed >= 0 && s_limiter_mode_prior_to_hold_interaction.has_value())
{
VMManager::SetLimiterMode(s_limiter_mode_prior_to_hold_interaction.value());
s_limiter_mode_prior_to_hold_interaction.reset();
}
})
DEFINE_HOTKEY("IncreaseSpeed", "System", "Increase Target Speed", [](s32 pressed) {
if (!pressed)
HotkeyAdjustTargetSpeed(0.1);
})
DEFINE_HOTKEY("DecreaseSpeed", "System", "Decrease Target Speed", [](s32 pressed) {
if (!pressed)
HotkeyAdjustTargetSpeed(-0.1);
})
DEFINE_HOTKEY("FrameAdvance", "System", "Frame Advance", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
VMManager::FrameAdvance(1);
})
DEFINE_HOTKEY("ShutdownVM", "System", "Shut Down Virtual Machine", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
Host::RequestVMShutdown(true, true, EmuConfig.SaveStateOnShutdown);
})
DEFINE_HOTKEY("ResetVM", "System", "Reset Virtual Machine", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
VMManager::Reset();
})
DEFINE_HOTKEY("InputRecToggleMode", "System", "Toggle Input Recording Mode", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
g_InputRecordingControls.RecordModeToggle();
})
DEFINE_HOTKEY("PreviousSaveStateSlot", "Save States", "Select Previous Save Slot", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
HotkeyCycleSaveSlot(-1);
})
DEFINE_HOTKEY("NextSaveStateSlot", "Save States", "Select Next Save Slot", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
HotkeyCycleSaveSlot(1);
})
DEFINE_HOTKEY("SaveStateToSlot", "Save States", "Save State To Selected Slot", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
VMManager::SaveStateToSlot(s_current_save_slot);
})
DEFINE_HOTKEY("LoadStateFromSlot", "Save States", "Load State From Selected Slot", [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
HotkeyLoadStateSlot(s_current_save_slot);
})
#define DEFINE_HOTKEY_SAVESTATE_X(slotnum) DEFINE_HOTKEY("SaveStateToSlot" #slotnum, \
"Save States", "Save State To Slot " #slotnum, [](s32 pressed) { if (!pressed) HotkeySaveStateSlot(slotnum); })
#define DEFINE_HOTKEY_LOADSTATE_X(slotnum) DEFINE_HOTKEY("LoadStateFromSlot" #slotnum, \
"Save States", "Load State From Slot " #slotnum, [](s32 pressed) { \
if (!pressed) \
HotkeyLoadStateSlot(slotnum); \
})
DEFINE_HOTKEY_SAVESTATE_X(1)
DEFINE_HOTKEY_LOADSTATE_X(1)
DEFINE_HOTKEY_SAVESTATE_X(2)
DEFINE_HOTKEY_LOADSTATE_X(2)
DEFINE_HOTKEY_SAVESTATE_X(3)
DEFINE_HOTKEY_LOADSTATE_X(3)
DEFINE_HOTKEY_SAVESTATE_X(4)
DEFINE_HOTKEY_LOADSTATE_X(4)
DEFINE_HOTKEY_SAVESTATE_X(5)
DEFINE_HOTKEY_LOADSTATE_X(5)
DEFINE_HOTKEY_SAVESTATE_X(6)
DEFINE_HOTKEY_LOADSTATE_X(6)
DEFINE_HOTKEY_SAVESTATE_X(7)
DEFINE_HOTKEY_LOADSTATE_X(7)
DEFINE_HOTKEY_SAVESTATE_X(8)
DEFINE_HOTKEY_LOADSTATE_X(8)
DEFINE_HOTKEY_SAVESTATE_X(9)
DEFINE_HOTKEY_LOADSTATE_X(9)
DEFINE_HOTKEY_SAVESTATE_X(10)
DEFINE_HOTKEY_LOADSTATE_X(10)
#undef DEFINE_HOTKEY_SAVESTATE_X
#undef DEFINE_HOTKEY_LOADSTATE_X
END_HOTKEY_LIST()
#ifdef _WIN32
#include "common/RedtapeWindows.h"

View File

@ -152,6 +152,9 @@ namespace VMManager
/// Returns true if the specified path is a save state.
bool IsSaveStateFileName(const std::string_view& path);
/// Returns true if the specified path is a disc image.
bool IsDiscFileName(const std::string_view& path);
/// Returns true if the specified path is a disc/elf/etc.
bool IsLoadableFileName(const std::string_view& path);
@ -198,6 +201,12 @@ namespace VMManager
namespace Host
{
/// Called with the settings lock held, when system settings are being loaded (should load input sources, etc).
void LoadSettings(SettingsInterface& si, std::unique_lock<std::mutex>& lock);
/// Called after settings are updated.
void CheckForSettingsChanges(const Pcsx2Config& old_config);
/// Called when the VM is starting initialization, but has not been completed yet.
void OnVMStarting();
@ -216,6 +225,10 @@ namespace Host
/// Called when performance metrics are updated, approximately once a second.
void OnPerformanceMetricsUpdated();
/// Looks up the serial and CRC for a game in the most efficient manner possible.
/// Implemented in the host because it may have a game list cache.
bool GetSerialAndCRCForFilename(const char* filename, std::string* serial, u32* crc);
/// Called when a save state is loading, before the file is processed.
void OnSaveStateLoading(const std::string_view& filename);
@ -230,7 +243,7 @@ namespace Host
void OnGameChanged(const std::string& disc_path, const std::string& game_serial, const std::string& game_name, u32 game_crc);
/// Provided by the host; called once per frame at guest vsync.
void PumpMessagesOnCPUThread();
void CPUThreadVSync();
/// Provided by the host; called when a state is saved, and the frontend should invalidate its save state cache.
void InvalidateSaveStateCache();

View File

@ -187,6 +187,7 @@
<ClCompile Include="DEV9\net.cpp" />
<ClCompile Include="DEV9\Win32\tap-win32.cpp" />
<ClCompile Include="Frontend\CommonHost.cpp" />
<ClCompile Include="Frontend\CommonHotkeys.cpp" />
<ClCompile Include="Frontend\D3D11HostDisplay.cpp" />
<ClCompile Include="Frontend\D3D12HostDisplay.cpp" />
<ClCompile Include="Frontend\FullscreenUI.cpp" />
@ -197,7 +198,7 @@
<ClCompile Include="Frontend\imgui_impl_dx12.cpp" />
<ClCompile Include="Frontend\imgui_impl_opengl3.cpp" />
<ClCompile Include="Frontend\imgui_impl_vulkan.cpp" />
<ClCompile Include="Frontend\INISettingsInterface.cpp" />
<ClCompile Include="INISettingsInterface.cpp" />
<ClCompile Include="Frontend\InputManager.cpp" />
<ClCompile Include="Frontend\InputSource.cpp" />
<ClCompile Include="Frontend\LayeredSettingsInterface.cpp" />
@ -520,7 +521,7 @@
<ClInclude Include="Frontend\imgui_impl_dx12.h" />
<ClInclude Include="Frontend\imgui_impl_opengl3.h" />
<ClInclude Include="Frontend\imgui_impl_vulkan.h" />
<ClInclude Include="Frontend\INISettingsInterface.h" />
<ClInclude Include="INISettingsInterface.h" />
<ClInclude Include="Frontend\InputManager.h" />
<ClInclude Include="Frontend\InputSource.h" />
<ClInclude Include="Frontend\LayeredSettingsInterface.h" />
@ -817,4 +818,4 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>
</Project>

View File

@ -1172,7 +1172,7 @@
<ClCompile Include="Frontend\GameList.cpp">
<Filter>Host</Filter>
</ClCompile>
<ClCompile Include="Frontend\INISettingsInterface.cpp">
<ClCompile Include="INISettingsInterface.cpp">
<Filter>Host</Filter>
</ClCompile>
<ClCompile Include="Frontend\InputManager.cpp">
@ -1284,6 +1284,9 @@
<ClCompile Include="Frontend\CommonHost.cpp">
<Filter>Host</Filter>
</ClCompile>
<ClCompile Include="Frontend\CommonHotkeys.cpp">
<Filter>Host</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Patch.h">
@ -2037,7 +2040,7 @@
<ClInclude Include="Frontend\GameList.h">
<Filter>Host</Filter>
</ClInclude>
<ClInclude Include="Frontend\INISettingsInterface.h">
<ClInclude Include="INISettingsInterface.h">
<Filter>Host</Filter>
</ClInclude>
<ClInclude Include="Frontend\InputManager.h">