aboutsummaryrefslogtreecommitdiff
path: root/src/qt_common/game_list/model.cpp
diff options
context:
space:
mode:
authorAlex <78863999+Sssnowyyy@users.noreply.github.com>2026-10-31 10:54:52 -0400
committerGitHub <noreply@github.com>2026-10-31 15:54:52 +0100
commitee2d55ee497c9467c8df82515165a21eac13fff5 (patch)
treecf30cc700b791838380f6f3019d70ceae4250dd0 /src/qt_common/game_list/model.cpp
parent01423a2470ee8a604218c1a6d5a0be6769624078 (diff)
boot Pokopia past audio init (Switch 2 heap limits, aud:u 1, stpl:u) (#77)
* game_list: don't free the worker while it is processing events OnPopulatingCompleted runs a nested event loop from inside GameListWorker::ProcessEvents. If the directory watcher fires there, the repopulate destroys the worker while ProcessEvents is still on the stack and the next lock hits a freed mutex. Stop the worker synchronously but free it with deleteLater, and stop ProcessEvents once it has been replaced. Assisted-by: Claude Opus 5.5 (code changes, debugging and commit message) * Fix Switch 2 heap limits and game list reloads during emulation - SetHeapSize rejected heaps of 8 GiB or more (Switch 1's MainMemorySizeMax), so Switch 2 titles that size their heap from the 12 GiB layout (Pokopia asks for 9.5 GiB) got ResultInvalidSize and aborted with 2001-0101. Allow up to the memory the active layout provides. - Grow the 39-bit heap region from 8 to 16 GiB so such a heap fits. - Skip watcher-driven game list reloads while a game runs: Repopulate calls CreateFactories, which replaces content providers the running game reads (segfault in ContentProviderUnion::GetEntry). Stopping emulation already repopulates the list. Assisted-by: Claude Opus 5.5 (code changes, debugging and commit message) * nx2: answer aud:u 1 with an IAudioOutManager nn::audio::OpenAudioOut gets its manager from aud:u command 1 and calls OpenAudioOut through slot 1 of the returned object. The auto stub returned no object, so Pokopia jumped through a null vtable 5 s into boot and never got past its first frame. Assisted-by: Claude Opus 5.5 (code changes, debugging and commit message) * nx2: add a stpl:u (stream play) stub with a user service nn::streamplay::detail::GetUserService opens a session with stpl:u 0 and attaches a system event to the handle command 300 returns. The generic missing-service stub returned no session, so Pokopia's first nn::streamplay call jumped through null right after audio setup. Assisted-by: Claude Opus 5.5 (code changes, debugging and commit message)
Diffstat (limited to 'src/qt_common/game_list/model.cpp')
-rw-r--r--src/qt_common/game_list/model.cpp23
1 files changed, 21 insertions, 2 deletions
diff --git a/src/qt_common/game_list/model.cpp b/src/qt_common/game_list/model.cpp
index 708ef576c6..4f3916b04d 100644
--- a/src/qt_common/game_list/model.cpp
+++ b/src/qt_common/game_list/model.cpp
@@ -49,7 +49,7 @@ GameListModel::~GameListModel() = default;
void GameListModel::PopulateAsync(QVector<UISettings::GameDir>& game_dirs) {
emit PopulatingStarted();
- current_worker.reset();
+ StopWorker();
removeRows(0, rowCount());
current_worker = std::make_unique<GameListWorker>(vfs, provider, game_dirs,
@@ -157,8 +157,27 @@ void GameListModel::RemoveFavorite(u64 program_id) {
}
}
+void GameListModel::StopWorker() {
+ if (!current_worker) {
+ return;
+ }
+
+ // The worker may still be inside ProcessEvents further up the stack (a nested event loop
+ // can trigger a repopulate), so stop it now but defer freeing it to the event loop.
+ current_worker->disconnect();
+ current_worker->Stop();
+ current_worker.release()->deleteLater();
+}
+
void GameListModel::Repopulate() {
- current_worker.reset();
+ // CreateFactories replaces the content providers a running game reads from. Stopping
+ // emulation repopulates the list anyway, so skip watcher-driven reloads until then.
+ if (QtCommon::system->IsPoweredOn()) {
+ LOG_INFO(Frontend, "Emulation is running, deferring game list reload.");
+ return;
+ }
+
+ StopWorker();
QtCommon::system->GetFileSystemController().CreateFactories(*QtCommon::vfs);
PopulateAsync(UISettings::values.game_dirs);
}