From 4214c301ef32d3e2fbff1a0747fa657a002522eb Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Sat, 9 Mar 2024 20:18:40 -0500 Subject: [PATCH] Refactor AchievementsWindow::UpdateData to take a partial update parameter UpdateData in AchievementsWindow now only updates the components being requested, massively improving the window's performance. The parameter is UpdatedItems in AchievementManager, which tracks which portions of the system have been updated for every update callback. --- Source/Core/Core/AchievementManager.cpp | 63 +++++++++++-------- Source/Core/Core/AchievementManager.h | 19 +++++- .../Achievements/AchievementHeaderWidget.cpp | 4 +- .../AchievementLeaderboardWidget.cpp | 2 - .../AchievementProgressWidget.cpp | 2 - .../Achievements/AchievementsWindow.cpp | 41 +++++++++--- .../Achievements/AchievementsWindow.h | 4 +- Source/Core/DolphinQt/MainWindow.cpp | 1 + 8 files changed, 88 insertions(+), 48 deletions(-) diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index 1c10b3b67e..2386cb25f8 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -61,9 +61,9 @@ void AchievementManager::SetUpdateCallback(UpdateCallback callback) m_update_callback = std::move(callback); if (!m_update_callback) - m_update_callback = [] {}; + m_update_callback = [](UpdatedItems) {}; - m_update_callback(); + m_update_callback(UpdatedItems{.all = true}); } void AchievementManager::Login(const std::string& password) @@ -147,22 +147,26 @@ bool AchievementManager::IsGameLoaded() const void AchievementManager::FetchPlayerBadge() { - FetchBadge(&m_player_badge, RC_IMAGE_TYPE_USER, [](const AchievementManager& manager) { - auto* user_info = rc_client_get_user_info(manager.m_client); - if (!user_info) - return std::string(""); - return std::string(user_info->display_name); - }); + FetchBadge(&m_player_badge, RC_IMAGE_TYPE_USER, + [](const AchievementManager& manager) { + auto* user_info = rc_client_get_user_info(manager.m_client); + if (!user_info) + return std::string(""); + return std::string(user_info->display_name); + }, + {.player_icon = true}); } void AchievementManager::FetchGameBadges() { - FetchBadge(&m_game_badge, RC_IMAGE_TYPE_GAME, [](const AchievementManager& manager) { - auto* game_info = rc_client_get_game_info(manager.m_client); - if (!game_info) - return std::string(""); - return std::string(game_info->badge_name); - }); + FetchBadge(&m_game_badge, RC_IMAGE_TYPE_GAME, + [](const AchievementManager& manager) { + auto* game_info = rc_client_get_game_info(manager.m_client); + if (!game_info) + return std::string(""); + return std::string(game_info->badge_name); + }, + {.game_icon = true}); if (!rc_client_has_achievements(m_client)) return; @@ -188,7 +192,8 @@ void AchievementManager::FetchGameBadges() return std::string(""); return std::string( rc_client_get_achievement_info(manager.m_client, achievement_id)->badge_name); - }); + }, + {.achievements = {achievement_id}}); FetchBadge( &m_locked_badges[achievement_id], RC_IMAGE_TYPE_ACHIEVEMENT_LOCKED, [achievement_id](const AchievementManager& manager) { @@ -196,7 +201,8 @@ void AchievementManager::FetchGameBadges() return std::string(""); return std::string( rc_client_get_achievement_info(manager.m_client, achievement_id)->badge_name); - }); + }, + {.achievements = {achievement_id}}); } } rc_client_destroy_achievement_list(achievement_list); @@ -226,7 +232,7 @@ void AchievementManager::DoFrame() GenerateRichPresence(Core::CPUThreadGuard{*m_system}); m_queue.EmplaceItem([this] { PingRichPresence(m_rich_presence); }); m_last_ping_time = current_time; - m_update_callback(); + m_update_callback(UpdatedItems{.rich_presence = true}); } } @@ -394,13 +400,13 @@ void AchievementManager::SetDisabled(bool disable) INFO_LOG_FMT(ACHIEVEMENTS, "Achievement Manager has been disabled."); OSD::AddMessage("Please close all games to re-enable achievements.", OSD::Duration::VERY_LONG, OSD::Color::RED); - m_update_callback(); + m_update_callback(UpdatedItems{.all = true}); } if (previously_disabled && !disable) { INFO_LOG_FMT(ACHIEVEMENTS, "Achievement Manager has been re-enabled."); - m_update_callback(); + m_update_callback(UpdatedItems{.all = true}); } }; @@ -481,7 +487,7 @@ void AchievementManager::CloseGame() } } - m_update_callback(); + m_update_callback(UpdatedItems{.all = true}); INFO_LOG_FMT(ACHIEVEMENTS, "Game closed."); } @@ -495,7 +501,7 @@ void AchievementManager::Logout() Config::SetBaseOrCurrent(Config::RA_API_TOKEN, ""); } - m_update_callback(); + m_update_callback(UpdatedItems{.all = true}); INFO_LOG_FMT(ACHIEVEMENTS, "Logged out from server."); } @@ -655,7 +661,7 @@ void AchievementManager::LeaderboardEntriesCallback(int result, const char* erro memcpy(map_entry.score.data(), response_entry.display, FORMAT_SIZE); map_entry.rank = response_entry.rank; } - AchievementManager::GetInstance().m_update_callback(); + AchievementManager::GetInstance().m_update_callback({.leaderboards = {leaderboard_id}}); } void AchievementManager::GenerateRichPresence(const Core::CPUThreadGuard& guard) @@ -701,6 +707,7 @@ void AchievementManager::LoadGameCallback(int result, const char* error_message, AchievementManager::GetInstance().FetchGameBadges(); AchievementManager::GetInstance().m_system = &Core::System::GetInstance(); + AchievementManager::GetInstance().m_update_callback({.all = true}); } void AchievementManager::DisplayWelcomeMessage() @@ -987,15 +994,17 @@ u32 AchievementManager::MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_ } void AchievementManager::FetchBadge(AchievementManager::BadgeStatus* badge, u32 badge_type, - const AchievementManager::BadgeNameFunction function) + const AchievementManager::BadgeNameFunction function, + const UpdatedItems callback_data) { if (!m_client || !HasAPIToken() || !Config::Get(Config::RA_BADGES_ENABLED)) { - m_update_callback(); + m_update_callback(callback_data); return; } - m_image_queue.EmplaceItem([this, badge, badge_type, function = std::move(function)] { + m_image_queue.EmplaceItem([this, badge, badge_type, function = std::move(function), + callback_data = std::move(callback_data)] { std::string name_to_fetch; { std::lock_guard lg{m_lock}; @@ -1019,7 +1028,7 @@ void AchievementManager::FetchBadge(AchievementManager::BadgeStatus* badge, u32 WARN_LOG_FMT(ACHIEVEMENTS, "RetroAchievements connection failed on image request.\n URL: {}", api_request.url); rc_api_destroy_request(&api_request); - m_update_callback(); + m_update_callback(callback_data); return; } @@ -1036,7 +1045,7 @@ void AchievementManager::FetchBadge(AchievementManager::BadgeStatus* badge, u32 badge->badge = std::move(fetched_badge); badge->name = std::move(name_to_fetch); - m_update_callback(); + m_update_callback(callback_data); }); } diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h index 9283401461..da816df6a5 100644 --- a/Source/Core/Core/AchievementManager.h +++ b/Source/Core/Core/AchievementManager.h @@ -50,7 +50,6 @@ public: UNKNOWN_FAILURE }; using ResponseCallback = std::function; - using UpdateCallback = std::function; using BadgeNameFunction = std::function; struct PointSpread @@ -116,6 +115,19 @@ public: std::unordered_map entries; }; + struct UpdatedItems + { + bool all = false; + bool player_icon = false; + bool game_icon = false; + bool all_achievements = false; + std::set achievements{}; + bool all_leaderboards = false; + std::set leaderboards{}; + bool rich_presence = false; + }; + using UpdateCallback = std::function; + static AchievementManager& GetInstance(); void Init(); void SetUpdateCallback(UpdateCallback callback); @@ -213,14 +225,15 @@ private: static void RequestV2(const rc_api_request_t* request, rc_client_server_callback_t callback, void* callback_data, rc_client_t* client); static u32 MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_client_t* client); - void FetchBadge(BadgeStatus* badge, u32 badge_type, const BadgeNameFunction function); + void FetchBadge(BadgeStatus* badge, u32 badge_type, const BadgeNameFunction function, + const UpdatedItems callback_data); static void EventHandler(const rc_client_event_t* event, rc_client_t* client); rc_runtime_t m_runtime{}; rc_client_t* m_client{}; Core::System* m_system{}; bool m_is_runtime_initialized = false; - UpdateCallback m_update_callback = [] {}; + UpdateCallback m_update_callback = [](const UpdatedItems&) {}; std::unique_ptr m_loading_volume; bool m_disabled = false; BadgeStatus m_player_badge; diff --git a/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp index bf151a77a1..5ae4f72676 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp @@ -62,13 +62,11 @@ AchievementHeaderWidget::AchievementHeaderWidget(QWidget* parent) : QWidget(pare m_total->setContentsMargins(0, 0, 0, 0); m_total->setAlignment(Qt::AlignTop); setLayout(m_total); - - std::lock_guard lg{AchievementManager::GetInstance().GetLock()}; - UpdateData(); } void AchievementHeaderWidget::UpdateData() { + std::lock_guard lg{AchievementManager::GetInstance().GetLock()}; auto& instance = AchievementManager::GetInstance(); if (!instance.HasAPIToken()) { diff --git a/Source/Core/DolphinQt/Achievements/AchievementLeaderboardWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementLeaderboardWidget.cpp index 6cb1892643..d2a52970f8 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementLeaderboardWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementLeaderboardWidget.cpp @@ -24,8 +24,6 @@ AchievementLeaderboardWidget::AchievementLeaderboardWidget(QWidget* parent) : QW m_common_box = new QGroupBox(); m_common_layout = new QGridLayout(); - UpdateData(true); - m_common_box->setLayout(m_common_layout); auto* layout = new QVBoxLayout; diff --git a/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp index 548bd5b9c1..0164ee6a78 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp @@ -27,8 +27,6 @@ AchievementProgressWidget::AchievementProgressWidget(QWidget* parent) : QWidget( m_common_box = new QGroupBox(); m_common_layout = new QVBoxLayout(); - UpdateData(true); - m_common_box->setLayout(m_common_layout); auto* layout = new QVBoxLayout; diff --git a/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp b/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp index 6f26811a49..b796b9dc3e 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp @@ -28,11 +28,13 @@ AchievementsWindow::AchievementsWindow(QWidget* parent) : QDialog(parent) CreateMainLayout(); ConnectWidgets(); AchievementManager::GetInstance().SetUpdateCallback( - [this] { QueueOnObject(this, &AchievementsWindow::UpdateData); }); + [this](AchievementManager::UpdatedItems updated_items) { + QueueOnObject(this, [this, updated_items = std::move(updated_items)] { + AchievementsWindow::UpdateData(std::move(updated_items)); + }); + }); connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, - &AchievementsWindow::UpdateData); - - UpdateData(); + [this] { AchievementsWindow::UpdateData({.all = true}); }); } void AchievementsWindow::showEvent(QShowEvent* event) @@ -71,19 +73,38 @@ void AchievementsWindow::ConnectWidgets() connect(m_button_box, &QDialogButtonBox::rejected, this, &QDialog::reject); } -void AchievementsWindow::UpdateData() +void AchievementsWindow::UpdateData(AchievementManager::UpdatedItems updated_items) { + m_settings_widget->UpdateData(); + if (updated_items.all) + { + m_header_widget->UpdateData(); + m_progress_widget->UpdateData(true); + m_leaderboard_widget->UpdateData(true); + } + else + { + if (updated_items.player_icon || updated_items.game_icon || updated_items.rich_presence || + updated_items.all_achievements || updated_items.achievements.size() > 0) + { + m_header_widget->UpdateData(); + } + if (updated_items.all_achievements) + m_progress_widget->UpdateData(false); + else if (updated_items.achievements.size() > 0) + m_progress_widget->UpdateData(updated_items.achievements); + if (updated_items.all_leaderboards) + m_leaderboard_widget->UpdateData(false); + else if (updated_items.leaderboards.size() > 0) + m_leaderboard_widget->UpdateData(updated_items.leaderboards); + } + { auto& instance = AchievementManager::GetInstance(); std::lock_guard lg{instance.GetLock()}; const bool is_game_loaded = instance.IsGameLoaded(); - - m_header_widget->UpdateData(); m_header_widget->setVisible(instance.HasAPIToken()); - m_settings_widget->UpdateData(); - m_progress_widget->UpdateData(true); m_tab_widget->setTabVisible(1, is_game_loaded); - m_leaderboard_widget->UpdateData(true); m_tab_widget->setTabVisible(2, is_game_loaded); } update(); diff --git a/Source/Core/DolphinQt/Achievements/AchievementsWindow.h b/Source/Core/DolphinQt/Achievements/AchievementsWindow.h index 751749fbc3..3012707b3d 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementsWindow.h +++ b/Source/Core/DolphinQt/Achievements/AchievementsWindow.h @@ -6,6 +6,8 @@ #ifdef USE_RETRO_ACHIEVEMENTS #include +#include "Core/AchievementManager.h" + class AchievementHeaderWidget; class AchievementLeaderboardWidget; class AchievementSettingsWidget; @@ -19,7 +21,7 @@ class AchievementsWindow : public QDialog Q_OBJECT public: explicit AchievementsWindow(QWidget* parent); - void UpdateData(); + void UpdateData(AchievementManager::UpdatedItems updated_items); void ForceSettingsTab(); private: diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index aacf4f933b..f1c6951595 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -2005,6 +2005,7 @@ void MainWindow::ShowAchievementsWindow() m_achievements_window->show(); m_achievements_window->raise(); m_achievements_window->activateWindow(); + m_achievements_window->UpdateData(AchievementManager::UpdatedItems{.all = true}); } void MainWindow::ShowAchievementSettings()