Fix Emulation boot recursion

This commit is contained in:
Elad 2024-11-26 12:09:02 +02:00
parent 378a69ea85
commit 07df91d4e8
4 changed files with 85 additions and 4 deletions

View File

@ -142,6 +142,7 @@ void fmt_class_string<game_boot_result>::format(std::string& out, u64 arg)
case game_boot_result::savestate_version_unsupported: return "Savestate versioning data differs from your RPCS3 build.\nTry to use an older or newer RPCS3 build.\nEspecially if you know the build that created the savestate.";
case game_boot_result::still_running: return "Game is still running";
case game_boot_result::already_added: return "Game was already added";
case game_boot_result::currently_restricted: return "Booting is restricted at the time being";
}
return unknown;
});
@ -802,7 +803,7 @@ std::string Emulator::GetBackgroundPicturePath() const
bool Emulator::BootRsxCapture(const std::string& path)
{
if (m_state != system_state::stopped)
if (m_state != system_state::stopped || m_restrict_emu_state_change)
{
return false;
}
@ -928,6 +929,11 @@ game_boot_result Emulator::GetElfPathFromDir(std::string& elf_path, const std::s
game_boot_result Emulator::BootGame(const std::string& path, const std::string& title_id, bool direct, cfg_mode config_mode, const std::string& config_path)
{
if (m_restrict_emu_state_change)
{
return game_boot_result::currently_restricted;
}
auto save_args = std::make_tuple(m_path, m_path_original, argv, envp, data, disc, klic, hdd1, m_config_mode, m_config_path);
auto restore_on_no_boot = [&](game_boot_result result)
@ -978,11 +984,18 @@ void Emulator::SetForceBoot(bool force_boot)
game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, usz recursion_count)
{
if (m_restrict_emu_state_change)
{
return game_boot_result::currently_restricted;
}
if (m_state != system_state::stopped)
{
return game_boot_result::still_running;
}
const auto guard = MakeEmulationStateGuard();
// Enable logging
rpcs3::utils::configure_logs(true);

View File

@ -57,6 +57,7 @@ enum class game_boot_result : u32
savestate_version_unsupported,
still_running,
already_added,
currently_restricted,
};
constexpr bool is_error(game_boot_result res)
@ -123,6 +124,7 @@ class Emulator final
atomic_t<u64> m_pause_amend_time{0}; // increased when resumed
atomic_t<u64> m_stop_ctr{1}; // Increments when emulation is stopped
atomic_t<bool> m_emu_state_close_pending = false;
atomic_t<u64> m_restrict_emu_state_change{0};
games_config m_games_config;
@ -206,8 +208,13 @@ public:
enum class stop_counter_t : u64{};
// Returns a different value each time we start a new emulation.
stop_counter_t GetEmulationIdentifier() const
stop_counter_t GetEmulationIdentifier(bool subtract_one = false) const
{
if (subtract_one)
{
return stop_counter_t{m_stop_ctr - 1};
}
return stop_counter_t{+m_stop_ctr};
}
@ -338,6 +345,41 @@ public:
return m_config_mode == cfg_mode::continuous;
}
class emulation_state_guard_t
{
class Emulator* _this = nullptr;
bool active = true;
public:
explicit emulation_state_guard_t(Emulator* this0) noexcept
: _this(this0)
{
_this->m_restrict_emu_state_change++;
}
~emulation_state_guard_t() noexcept
{
if (active)
{
_this->m_restrict_emu_state_change--;
}
}
emulation_state_guard_t(emulation_state_guard_t&& rhs) noexcept
{
_this = rhs._this;
active = std::exchange(rhs.active, false);
}
emulation_state_guard_t& operator=(const emulation_state_guard_t&) = delete;
emulation_state_guard_t(const emulation_state_guard_t&) = delete;
};
emulation_state_guard_t MakeEmulationStateGuard()
{
return emulation_state_guard_t{this};
}
game_boot_result BootGame(const std::string& path, const std::string& title_id = "", bool direct = false, cfg_mode config_mode = cfg_mode::custom, const std::string& config_path = "");
bool BootRsxCapture(const std::string& path);
@ -349,6 +391,11 @@ public:
void FixGuestTime();
void FinalizeRunRequest();
bool IsBootingRestricted() const
{
return m_restrict_emu_state_change != 0;
}
private:
struct savestate_stage
{

View File

@ -195,13 +195,17 @@ void gui_settings::ShowInfoBox(const QString& title, const QString& text, const
bool gui_settings::GetBootConfirmation(QWidget* parent, const gui_save& gui_save_entry)
{
auto info = Emu.GetEmulationIdentifier();
// Ensure no game has booted inbetween
const auto guard = Emu.MakeEmulationStateGuard();
const auto info = Emu.GetEmulationIdentifier();
const auto old_status = Emu.GetStatus(false);
qt_events_aware_op(16, [&]()
{
if (Emu.GetStatus(false) != system_state::stopping)
{
ensure(info == Emu.GetEmulationIdentifier());
ensure(info == Emu.GetEmulationIdentifier(old_status == system_state::stopping ? true : false));
return true;
}

View File

@ -562,6 +562,7 @@ void main_window::show_boot_error(game_boot_result status)
break;
case game_boot_result::firmware_missing: // Handled elsewhere
case game_boot_result::already_added: // Handled elsewhere
case game_boot_result::currently_restricted:
case game_boot_result::no_errors:
return;
case game_boot_result::generic_error:
@ -576,12 +577,18 @@ void main_window::show_boot_error(game_boot_result status)
msg->setTextFormat(Qt::RichText);
msg->setStandardButtons(QMessageBox::Ok);
msg->setText(tr("Booting failed: %1 %2").arg(message).arg(link));
msg->setParent(this);
msg->setAttribute(Qt::WA_DeleteOnClose);
msg->open();
}
void main_window::Boot(const std::string& path, const std::string& title_id, bool direct, bool refresh_list, cfg_mode config_mode, const std::string& config_path)
{
if (Emu.IsBootingRestricted())
{
return;
}
if (!m_gui_settings->GetBootConfirmation(this, gui::ib_confirm_boot))
{
return;
@ -3776,6 +3783,11 @@ void main_window::RemoveFirmwareCache()
void main_window::CreateFirmwareCache()
{
if (Emu.IsBootingRestricted())
{
return;
}
if (!m_gui_settings->GetBootConfirmation(this))
{
return;
@ -4092,6 +4104,11 @@ void main_window::dropEvent(QDropEvent* event)
}
case drop_type::drop_game: // import valid games to gamelist (games.yaml)
{
if (Emu.IsBootingRestricted())
{
return;
}
if (!m_gui_settings->GetBootConfirmation(this))
{
return;