Skip to content

Commit

Permalink
FullscreenUI: Fix several more unsafe reads
Browse files Browse the repository at this point in the history
  • Loading branch information
stenzek committed Jan 20, 2025
1 parent cc0ccf2 commit 78902d7
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 91 deletions.
181 changes: 91 additions & 90 deletions src/core/fullscreen_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -419,9 +419,9 @@ static bool InitializeSaveStateListEntryFromSerial(SaveStateListEntry* li, const
bool global);
static bool InitializeSaveStateListEntryFromPath(SaveStateListEntry* li, std::string path, s32 slot, bool global);
static void ClearSaveStateEntryList();
static u32 PopulateSaveStateListEntries(const std::string& title, const std::string& serial);
static bool OpenLoadStateSelectorForGame(const std::string& game_path);
static bool OpenSaveStateSelector(bool is_loading);
static u32 PopulateSaveStateListEntries(const std::string& serial,
std::optional<ExtendedSaveStateInfo> undo_save_state);
static void OpenSaveStateSelector(const std::string& serial, const std::string& path, bool is_loading);
static void CloseSaveStateSelector();
static void DrawSaveStateSelector(bool is_loading);
static bool OpenLoadStateSelectorForGameResume(const GameList::Entry* entry);
Expand Down Expand Up @@ -486,7 +486,9 @@ struct ALIGN_TO_CACHE_LINE UIState
bool was_paused_on_quick_menu_open = false;
bool about_window_open = false;
bool achievements_login_window_open = false;
std::string current_game_subtitle;
std::string current_game_title;
std::string current_game_serial;
std::string current_game_path;
std::string achievements_user_badge_path;

// Resources
Expand Down Expand Up @@ -672,6 +674,15 @@ bool FullscreenUI::Initialize()
SwitchToLanding();
}

// in case we open the pause menu while the game is running
if (GPUThread::HasGPUBackend())
{
Host::RunOnCPUThread([]() {
if (System::IsValid())
FullscreenUI::OnRunningGameChanged(System::GetDiscPath(), System::GetGameSerial(), System::GetGameTitle());
});
}

LoadBackground();
UpdateRunIdleState();
ForceKeyNavEnabled();
Expand Down Expand Up @@ -758,32 +769,25 @@ void FullscreenUI::OnSystemDestroyed()
});
}

void FullscreenUI::OnRunningGameChanged()
void FullscreenUI::OnRunningGameChanged(const std::string& path, const std::string& serial, const std::string& title)
{
// NOTE: Called on CPU thread.
if (!IsInitialized())
return;

const std::string& path = System::GetDiscPath();
const std::string& serial = System::GetGameSerial();

std::string subtitle;
if (!serial.empty())
subtitle = fmt::format("{0} - {1}", serial, Path::GetFileName(path));
else
subtitle = {};

GPUThread::RunOnThread([subtitle = std::move(subtitle)]() mutable {
GPUThread::RunOnThread([path = path, title = title, serial = serial]() mutable {
if (!IsInitialized())
return;

s_state.current_game_subtitle = std::move(subtitle);
s_state.current_game_title = std::move(title);
s_state.current_game_serial = std::move(serial);
s_state.current_game_path = std::move(path);
});
}

void FullscreenUI::PauseForMenuOpen(bool set_pause_menu_open)
{
s_state.was_paused_on_quick_menu_open = (System::GetState() == System::State::Paused);
s_state.was_paused_on_quick_menu_open = GPUThread::IsSystemPaused();
if (!s_state.was_paused_on_quick_menu_open)
Host::RunOnCPUThread([]() { System::PauseSystem(true); });

Expand Down Expand Up @@ -894,7 +898,9 @@ void FullscreenUI::Shutdown(bool clear_state)
s_state.fullscreen_mode_list_cache = {};
s_state.graphics_adapter_list_cache = {};
s_state.hotkey_list_cache = {};
s_state.current_game_subtitle = {};
s_state.current_game_path = {};
s_state.current_game_serial = {};
s_state.current_game_title = {};
}

DestroyResources();
Expand Down Expand Up @@ -1301,7 +1307,7 @@ void FullscreenUI::DoChangeDiscFromFile()
};

OpenFileSelector(FSUI_ICONSTR(ICON_FA_COMPACT_DISC, "Select Disc Image"), false, std::move(callback),
GetDiscImageFilters(), std::string(Path::GetDirectory(System::GetDiscPath())));
GetDiscImageFilters(), std::string(Path::GetDirectory(s_state.current_game_path)));
});
}

Expand Down Expand Up @@ -1897,7 +1903,7 @@ void FullscreenUI::DrawStartGameWindow()
if (!AreAnyDialogsOpen())
{
if (ImGui::IsKeyPressed(ImGuiKey_NavGamepadMenu, false) || ImGui::IsKeyPressed(ImGuiKey_F1, false))
OpenSaveStateSelector(true);
OpenSaveStateSelector(std::string(), std::string(), true);
}

if (IsGamepadInputSource())
Expand Down Expand Up @@ -3311,14 +3317,14 @@ void FullscreenUI::SwitchToGameSettingsForSerial(std::string_view serial)

bool FullscreenUI::SwitchToGameSettings()
{
if (System::GetGameSerial().empty())
if (s_state.current_game_serial.empty())
return false;

auto lock = GameList::GetLock();
const GameList::Entry* entry = GameList::GetEntryForPath(System::GetDiscPath());
const GameList::Entry* entry = GameList::GetEntryForPath(s_state.current_game_path);
if (!entry)
{
SwitchToGameSettingsForSerial(System::GetGameSerial());
SwitchToGameSettingsForSerial(s_state.current_game_serial);
return true;
}
else
Expand Down Expand Up @@ -6477,20 +6483,19 @@ void FullscreenUI::DrawPauseMenu()

// title info
{
const std::string& title = System::GetGameTitle();
const std::string& serial = System::GetGameSerial();

if (!serial.empty())
buffer.format("{} - ", serial);
buffer.append(Path::GetFileName(System::GetDiscPath()));
if (!s_state.current_game_serial.empty())
buffer.format("{} - {}", s_state.current_game_serial, Path::GetFileName(s_state.current_game_path));
else
buffer.assign(Path::GetFileName(s_state.current_game_path));

const float image_width = 60.0f;
const float image_height = 60.0f;

const ImVec2 title_size(UIStyle.LargeFont->CalcTextSizeA(UIStyle.LargeFont->FontSize,
std::numeric_limits<float>::max(), -1.0f, title.c_str()));
const ImVec2 title_size(UIStyle.LargeFont->CalcTextSizeA(
UIStyle.LargeFont->FontSize, std::numeric_limits<float>::max(), -1.0f, s_state.current_game_title.c_str(),
s_state.current_game_title.c_str() + s_state.current_game_title.size()));
const ImVec2 subtitle_size(UIStyle.MediumFont->CalcTextSizeA(
UIStyle.MediumFont->FontSize, std::numeric_limits<float>::max(), -1.0f, buffer.c_str()));
UIStyle.MediumFont->FontSize, std::numeric_limits<float>::max(), -1.0f, buffer.c_str(), buffer.end_ptr()));

ImVec2 title_pos(display_size.x - LayoutScale(10.0f + image_width + 20.0f) - title_size.x,
display_size.y - LayoutScale(LAYOUT_FOOTER_HEIGHT) - LayoutScale(10.0f + image_height));
Expand Down Expand Up @@ -6522,8 +6527,9 @@ void FullscreenUI::DrawPauseMenu()
}
}

DrawShadowedText(dl, UIStyle.LargeFont, title_pos, text_color, title.c_str());
DrawShadowedText(dl, UIStyle.MediumFont, subtitle_pos, text_color, buffer.c_str());
DrawShadowedText(dl, UIStyle.LargeFont, title_pos, text_color, s_state.current_game_title.c_str(),
s_state.current_game_title.c_str() + s_state.current_game_title.size());
DrawShadowedText(dl, UIStyle.MediumFont, subtitle_pos, text_color, buffer.c_str(), buffer.end_ptr());

GPUTexture* const cover = GetCoverForCurrentGame();
const ImVec2 image_min(display_size.x - LayoutScale(10.0f + image_width),
Expand All @@ -6544,10 +6550,9 @@ void FullscreenUI::DrawPauseMenu()
const ImVec2 time_pos(display_size.x - LayoutScale(10.0f) - time_size.x, LayoutScale(10.0f));
DrawShadowedText(dl, UIStyle.LargeFont, time_pos, text_color, buffer.c_str(), buffer.end_ptr());

const std::string& serial = System::GetGameSerial();
if (!serial.empty())
if (!s_state.current_game_serial.empty())
{
const std::time_t cached_played_time = GameList::GetCachedPlayedTimeForSerial(serial);
const std::time_t cached_played_time = GameList::GetCachedPlayedTimeForSerial(s_state.current_game_serial);
const std::time_t session_time = static_cast<std::time_t>(System::GetSessionPlayedTime());

buffer.format(FSUI_FSTR("Session: {}"), GameList::FormatTimespan(session_time, true));
Expand Down Expand Up @@ -6588,7 +6593,7 @@ void FullscreenUI::DrawPauseMenu()
case PauseSubMenu::None:
{
// NOTE: Menu close must come first, because otherwise VM destruction options will race.
const bool has_game = GPUThread::HasGPUBackend() && !System::GetGameSerial().empty();
const bool has_game = GPUThread::HasGPUBackend();

if (DefaultActiveButton(FSUI_ICONSTR(ICON_FA_PLAY, "Resume Game"), false) || WantsToCloseMenu())
ClosePauseMenu();
Expand All @@ -6600,16 +6605,10 @@ void FullscreenUI::DrawPauseMenu()
}

if (ActiveButton(FSUI_ICONSTR(ICON_FA_UNDO, "Load State"), false, has_game))
{
if (OpenSaveStateSelector(true))
s_state.current_main_window = MainWindowType::None;
}
OpenSaveStateSelector(s_state.current_game_serial, s_state.current_game_path, true);

if (ActiveButton(FSUI_ICONSTR(ICON_FA_DOWNLOAD, "Save State"), false, has_game))
{
if (OpenSaveStateSelector(false))
s_state.current_main_window = MainWindowType::None;
}
OpenSaveStateSelector(s_state.current_game_serial, s_state.current_game_path, false);

if (ActiveButton(FSUI_ICONSTR(ICON_FA_GAMEPAD, "Toggle Analog"), false))
{
Expand All @@ -6634,7 +6633,7 @@ void FullscreenUI::DrawPauseMenu()

if (ActiveButton(FSUI_ICONSTR(ICON_FA_CAMERA, "Save Screenshot"), false))
{
System::SaveScreenshot();
Host::RunOnCPUThread([]() { System::SaveScreenshot(); });
ClosePauseMenu();
}

Expand Down Expand Up @@ -6779,22 +6778,19 @@ void FullscreenUI::ClearSaveStateEntryList()
s_state.save_state_selector_slots.clear();
}

u32 FullscreenUI::PopulateSaveStateListEntries(const std::string& title, const std::string& serial)
u32 FullscreenUI::PopulateSaveStateListEntries(const std::string& serial,
std::optional<ExtendedSaveStateInfo> undo_save_state)
{
ClearSaveStateEntryList();

if (s_state.save_state_selector_loading)
if (undo_save_state.has_value())
{
std::optional<ExtendedSaveStateInfo> ssi = System::GetUndoSaveStateInfo();
if (ssi)
{
SaveStateListEntry li;
li.title = FSUI_STR("Undo Load State");
li.summary = FSUI_STR("Restores the state of the system prior to the last state loaded.");
if (ssi->screenshot.IsValid())
li.preview_texture = g_gpu_device->FetchAndUploadTextureImage(ssi->screenshot);
s_state.save_state_selector_slots.push_back(std::move(li));
}
SaveStateListEntry li;
li.title = FSUI_STR("Undo Load State");
li.summary = FSUI_STR("Restores the state of the system prior to the last state loaded.");
if (undo_save_state->screenshot.IsValid())
li.preview_texture = g_gpu_device->FetchAndUploadTextureImage(undo_save_state->screenshot);
s_state.save_state_selector_slots.push_back(std::move(li));
}

if (!serial.empty())
Expand All @@ -6817,40 +6813,45 @@ u32 FullscreenUI::PopulateSaveStateListEntries(const std::string& title, const s
return static_cast<u32>(s_state.save_state_selector_slots.size());
}

bool FullscreenUI::OpenLoadStateSelectorForGame(const std::string& game_path)
void FullscreenUI::OpenSaveStateSelector(const std::string& serial, const std::string& path, bool is_loading)
{
auto lock = GameList::GetLock();
const GameList::Entry* entry = GameList::GetEntryForPath(game_path);
if (entry)
if (GPUThread::HasGPUBackend())
{
s_state.save_state_selector_loading = true;
if (PopulateSaveStateListEntries(entry->title, entry->serial) > 0)
// need to get the undo state, if any
Host::RunOnCPUThread([serial = serial, is_loading]() {
std::optional<ExtendedSaveStateInfo> undo_state = System::GetUndoSaveStateInfo();
GPUThread::RunOnThread([serial = std::move(serial), undo_state = std::move(undo_state), is_loading]() mutable {
s_state.save_state_selector_loading = is_loading;
s_state.save_state_selector_resuming = false;
s_state.save_state_selector_game_path = {};
if (PopulateSaveStateListEntries(serial, std::move(undo_state)) > 0)
{
s_state.current_main_window = MainWindowType::None;
s_state.save_state_selector_open = true;
QueueResetFocus(FocusResetType::PopupOpened);
}
else
{
ShowToast({}, FSUI_STR("No save states found."), Host::OSD_INFO_DURATION);
}
});
});
}
else
{
s_state.save_state_selector_loading = is_loading;
s_state.save_state_selector_resuming = false;
if (PopulateSaveStateListEntries(serial, std::nullopt) > 0)
{
s_state.save_state_selector_game_path = path;
s_state.save_state_selector_open = true;
s_state.save_state_selector_resuming = false;
s_state.save_state_selector_game_path = game_path;
return true;
}
else
{
s_state.save_state_selector_game_path = {};
ShowToast({}, FSUI_STR("No save states found."), Host::OSD_INFO_DURATION);
}
}

ShowToast({}, FSUI_STR("No save states found."), 5.0f);
return false;
}

bool FullscreenUI::OpenSaveStateSelector(bool is_loading)
{
s_state.save_state_selector_game_path = {};
s_state.save_state_selector_loading = is_loading;
s_state.save_state_selector_resuming = false;
if (PopulateSaveStateListEntries(System::GetGameTitle(), System::GetGameSerial()) > 0)
{
s_state.save_state_selector_open = true;
QueueResetFocus(FocusResetType::PopupOpened);
return true;
}

ShowToast({}, FSUI_STR("No save states found."), 5.0f);
return false;
}

void FullscreenUI::CloseSaveStateSelector()
Expand Down Expand Up @@ -7210,7 +7211,7 @@ bool FullscreenUI::OpenLoadStateSelectorForGameResume(const GameList::Entry* ent

void FullscreenUI::DrawResumeStateSelector()
{
ImGui::SetNextWindowSize(LayoutScale(800.0f, 602.0f));
ImGui::SetNextWindowSize(LayoutScale(800.0f, 605.0f));
ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::OpenPopup(FSUI_CSTR("Load Resume State"));

Expand Down Expand Up @@ -7934,7 +7935,7 @@ void FullscreenUI::HandleGameListOptions(const GameList::Entry* entry)
DoStartPath(entry_path, System::GetGameSaveStateFileName(entry_serial, -1));
break;
case 4: // Load State
OpenLoadStateSelectorForGame(entry_path);
OpenSaveStateSelector(entry_serial, entry_path, true);
break;
case 5: // Default Boot
DoStartPath(entry_path);
Expand Down Expand Up @@ -8259,7 +8260,7 @@ GPUTexture* FullscreenUI::GetCoverForCurrentGame()
{
auto lock = GameList::GetLock();

const GameList::Entry* entry = GameList::GetEntryForPath(System::GetDiscPath());
const GameList::Entry* entry = GameList::GetEntryForPath(s_state.current_game_path);
if (!entry)
return s_state.fallback_disc_texture.get();

Expand Down
2 changes: 1 addition & 1 deletion src/core/fullscreen_ui.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void CheckForConfigChanges(const GPUSettings& old_settings);
void OnSystemStarted();
void OnSystemResumed();
void OnSystemDestroyed();
void OnRunningGameChanged();
void OnRunningGameChanged(const std::string& path, const std::string& serial, const std::string& title);

#ifndef __ANDROID__
void OpenPauseMenu();
Expand Down
3 changes: 3 additions & 0 deletions src/core/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4208,6 +4208,9 @@ void System::UpdateRunningGame(const std::string& path, CDImage* image, bool boo

UpdateRichPresence(booting);

FullscreenUI::OnRunningGameChanged(s_state.running_game_path, s_state.running_game_serial,
s_state.running_game_title);

Host::OnGameChanged(s_state.running_game_path, s_state.running_game_serial, s_state.running_game_title);
}

Expand Down

0 comments on commit 78902d7

Please sign in to comment.