mirror of
https://github.com/stenzek/duckstation.git
synced 2025-06-07 12:05:52 +00:00
Qt: Avoid game list refresh on shutdown
We only need to invalidate the entries that have had their play times changed, not the entire list.
This commit is contained in:
parent
4e97420b3b
commit
2b7a4f8d19
@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
||||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||||
|
|
||||||
#include "game_list.h"
|
#include "game_list.h"
|
||||||
@ -24,6 +24,7 @@
|
|||||||
#include "common/path.h"
|
#include "common/path.h"
|
||||||
#include "common/progress_callback.h"
|
#include "common/progress_callback.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
|
#include "common/thirdparty/SmallVector.h"
|
||||||
#include "common/timer.h"
|
#include "common/timer.h"
|
||||||
|
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
@ -1223,50 +1224,35 @@ void GameList::AddPlayedTimeForSerial(const std::string& serial, std::time_t las
|
|||||||
static_cast<unsigned>(pt.total_played_time));
|
static_cast<unsigned>(pt.total_played_time));
|
||||||
|
|
||||||
std::unique_lock<std::recursive_mutex> lock(s_mutex);
|
std::unique_lock<std::recursive_mutex> lock(s_mutex);
|
||||||
for (GameList::Entry& entry : s_entries)
|
const GameDatabase::Entry* dbentry = GameDatabase::GetEntryForSerial(serial);
|
||||||
|
llvm::SmallVector<u32, 32> changed_indices;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < s_entries.size(); i++)
|
||||||
|
{
|
||||||
|
Entry& entry = s_entries[i];
|
||||||
|
if (entry.IsDisc())
|
||||||
{
|
{
|
||||||
if (entry.serial != serial)
|
if (entry.serial != serial)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
entry.last_played_time = pt.last_played_time;
|
entry.last_played_time = pt.last_played_time;
|
||||||
entry.total_played_time = pt.total_played_time;
|
entry.total_played_time = pt.total_played_time;
|
||||||
|
changed_indices.push_back(static_cast<u32>(i));
|
||||||
}
|
}
|
||||||
|
else if (entry.IsDiscSet())
|
||||||
// We don't need to update the disc sets if we're not running Big Picture, because Qt refreshes on system destory,
|
|
||||||
// which causes the disc set entries to get recreated.
|
|
||||||
if (FullscreenUI::IsInitialized())
|
|
||||||
{
|
{
|
||||||
const GameDatabase::Entry* dbentry = GameDatabase::GetEntryForSerial(serial);
|
if (!dbentry || entry.path != dbentry->disc_set_name)
|
||||||
if (dbentry && !dbentry->disc_set_serials.empty())
|
|
||||||
{
|
|
||||||
for (GameList::Entry& entry : s_entries)
|
|
||||||
{
|
|
||||||
if (entry.type != EntryType::DiscSet || entry.path != dbentry->disc_set_name)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
entry.last_played_time = 0;
|
// have to add here, because other discs are already included in the sum
|
||||||
entry.total_played_time = 0;
|
entry.last_played_time = pt.last_played_time;
|
||||||
|
entry.total_played_time += add_time;
|
||||||
// We shouldn't ever have duplicates for disc sets, so this should be fine.
|
changed_indices.push_back(static_cast<u32>(i));
|
||||||
const PlayedTimeMap ptm = LoadPlayedTimeMap(GetPlayedTimeFile());
|
}
|
||||||
for (const std::string& dsserial : dbentry->disc_set_serials)
|
|
||||||
{
|
|
||||||
const auto it = ptm.find(dsserial);
|
|
||||||
if (it == ptm.end())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
entry.last_played_time =
|
|
||||||
(entry.last_played_time == 0) ?
|
|
||||||
it->second.last_played_time :
|
|
||||||
((it->second.last_played_time != 0) ? std::max(entry.last_played_time, it->second.last_played_time) :
|
|
||||||
entry.last_played_time);
|
|
||||||
entry.total_played_time += it->second.total_played_time;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
if (!changed_indices.empty())
|
||||||
}
|
Host::OnGameListEntriesChanged(std::span<const u32>(changed_indices.begin(), changed_indices.end()));
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameList::ClearPlayedTimeForSerial(const std::string& serial)
|
void GameList::ClearPlayedTimeForSerial(const std::string& serial)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
||||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -150,4 +150,7 @@ void RefreshGameListAsync(bool invalidate_cache);
|
|||||||
|
|
||||||
/// Cancels game list refresh, if there is one in progress.
|
/// Cancels game list refresh, if there is one in progress.
|
||||||
void CancelGameListRefresh();
|
void CancelGameListRefresh();
|
||||||
|
|
||||||
|
/// Called when game list rows are updated.
|
||||||
|
void OnGameListEntriesChanged(std::span<const u32> changed_indices);
|
||||||
} // namespace Host
|
} // namespace Host
|
||||||
|
@ -194,6 +194,8 @@ GameListModel::GameListModel(float cover_scale, bool show_cover_titles, bool sho
|
|||||||
|
|
||||||
if (m_show_game_icons)
|
if (m_show_game_icons)
|
||||||
GameList::ReloadMemcardTimestampCache();
|
GameList::ReloadMemcardTimestampCache();
|
||||||
|
|
||||||
|
connect(g_emu_thread, &EmuThread::gameListRowsChanged, this, &GameListModel::rowsChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
GameListModel::~GameListModel()
|
GameListModel::~GameListModel()
|
||||||
@ -271,6 +273,28 @@ void GameListModel::coverLoaded(const std::string& path, const QPixmap& pixmap)
|
|||||||
invalidateCoverForPath(path);
|
invalidateCoverForPath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameListModel::rowsChanged(const QList<int>& rows)
|
||||||
|
{
|
||||||
|
const QList<int> roles_changed = {Qt::DisplayRole};
|
||||||
|
|
||||||
|
// try to collapse multiples
|
||||||
|
size_t start = 0;
|
||||||
|
size_t idx = 0;
|
||||||
|
const size_t size = rows.size();
|
||||||
|
for (; idx < size;)
|
||||||
|
{
|
||||||
|
if ((idx + 1) < size && rows[idx + 1] == (rows[idx] + 1))
|
||||||
|
{
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emit dataChanged(createIndex(rows[start], 0), createIndex(rows[idx], Column_Count - 1), roles_changed);
|
||||||
|
start = ++idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GameListModel::invalidateCoverForPath(const std::string& path)
|
void GameListModel::invalidateCoverForPath(const std::string& path)
|
||||||
{
|
{
|
||||||
std::optional<u32> row;
|
std::optional<u32> row;
|
||||||
|
@ -89,6 +89,7 @@ Q_SIGNALS:
|
|||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void coverLoaded(const std::string& path, const QPixmap& pixmap);
|
void coverLoaded(const std::string& path, const QPixmap& pixmap);
|
||||||
|
void rowsChanged(const QList<int>& rows);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVariant data(const QModelIndex& index, int role, const GameList::Entry* ge) const;
|
QVariant data(const QModelIndex& index, int role, const GameList::Entry* ge) const;
|
||||||
|
@ -621,10 +621,6 @@ void MainWindow::onSystemDestroyed()
|
|||||||
updateDisplayWidgetCursor();
|
updateDisplayWidgetCursor();
|
||||||
else
|
else
|
||||||
switchToGameListView();
|
switchToGameListView();
|
||||||
|
|
||||||
// reload played time
|
|
||||||
if (m_game_list_widget->isShowingGameList())
|
|
||||||
m_game_list_widget->refresh(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onRunningGameChanged(const QString& filename, const QString& game_serial, const QString& game_title)
|
void MainWindow::onRunningGameChanged(const QString& filename, const QString& game_serial, const QString& game_title)
|
||||||
|
@ -1397,6 +1397,15 @@ void Host::CancelGameListRefresh()
|
|||||||
QMetaObject::invokeMethod(g_main_window, "cancelGameListRefresh", Qt::BlockingQueuedConnection);
|
QMetaObject::invokeMethod(g_main_window, "cancelGameListRefresh", Qt::BlockingQueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Host::OnGameListEntriesChanged(std::span<const u32> changed_indices)
|
||||||
|
{
|
||||||
|
QList<int> changed_rows;
|
||||||
|
changed_rows.reserve(changed_indices.size());
|
||||||
|
for (const u32 row : changed_indices)
|
||||||
|
changed_rows.push_back(static_cast<int>(row));
|
||||||
|
emit g_emu_thread->gameListRowsChanged(changed_rows);
|
||||||
|
}
|
||||||
|
|
||||||
void EmuThread::loadState(const QString& filename)
|
void EmuThread::loadState(const QString& filename)
|
||||||
{
|
{
|
||||||
if (!isCurrentThread())
|
if (!isCurrentThread())
|
||||||
|
@ -141,6 +141,7 @@ Q_SIGNALS:
|
|||||||
void systemPaused();
|
void systemPaused();
|
||||||
void systemResumed();
|
void systemResumed();
|
||||||
void gameListRefreshed();
|
void gameListRefreshed();
|
||||||
|
void gameListRowsChanged(const QList<int>& rows_changed);
|
||||||
std::optional<WindowInfo> onAcquireRenderWindowRequested(RenderAPI render_api, bool fullscreen, bool render_to_main,
|
std::optional<WindowInfo> onAcquireRenderWindowRequested(RenderAPI render_api, bool fullscreen, bool render_to_main,
|
||||||
bool surfaceless, bool use_main_window_pos, Error* error);
|
bool surfaceless, bool use_main_window_pos, Error* error);
|
||||||
void onResizeRenderWindowRequested(qint32 width, qint32 height);
|
void onResizeRenderWindowRequested(qint32 width, qint32 height);
|
||||||
|
@ -597,6 +597,11 @@ void Host::CancelGameListRefresh()
|
|||||||
// noop
|
// noop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Host::OnGameListEntriesChanged(std::span<const u32> changed_indices)
|
||||||
|
{
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
BEGIN_HOTKEY_LIST(g_host_hotkeys)
|
BEGIN_HOTKEY_LIST(g_host_hotkeys)
|
||||||
END_HOTKEY_LIST()
|
END_HOTKEY_LIST()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user