From 9612b12e5c4e1e6f0ae7d7e32efb377fc72ac98e Mon Sep 17 00:00:00 2001
From: pineappleEA <pineaea@gmail.com>
Date: Tue, 8 Jun 2021 07:46:24 +0200
Subject: [PATCH] early-access version 1763

---
 README.md                                |  2 +-
 src/core/hle/kernel/hle_ipc.cpp          | 15 +++++++++++++++
 src/core/hle/kernel/hle_ipc.h            |  9 +++++----
 src/core/hle/kernel/k_server_session.cpp | 13 +++++++++----
 src/core/hle/kernel/kernel.cpp           | 18 ++++--------------
 src/yuzu/game_list.cpp                   | 10 ++++++++++
 src/yuzu/game_list.h                     |  2 ++
 src/yuzu/main.cpp                        |  6 ++++--
 src/yuzu/main.h                          |  8 +++++++-
 9 files changed, 57 insertions(+), 26 deletions(-)

diff --git a/README.md b/README.md
index 3f5e8c225..84bb03b64 100755
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 yuzu emulator early access
 =============
 
-This is the source code for early-access 1761.
+This is the source code for early-access 1763.
 
 ## Legal Notice
 
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 260af87e5..45aced99f 100755
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -41,6 +41,21 @@ SessionRequestManager::SessionRequestManager(KernelCore& kernel_) : kernel{kerne
 
 SessionRequestManager::~SessionRequestManager() = default;
 
+bool SessionRequestManager::HasSessionRequestHandler(const HLERequestContext& context) const {
+    if (IsDomain() && context.HasDomainMessageHeader()) {
+        const auto& message_header = context.GetDomainMessageHeader();
+        const auto object_id = message_header.object_id;
+
+        if (object_id > DomainHandlerCount()) {
+            LOG_CRITICAL(IPC, "object_id {} is too big!", object_id);
+            return false;
+        }
+        return DomainHandler(object_id - 1) != nullptr;
+    } else {
+        return session_handler != nullptr;
+    }
+}
+
 void SessionRequestHandler::ClientConnected(KServerSession* session) {
     session->SetSessionHandler(shared_from_this());
 }
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 2aaf93fca..a61870f8b 100755
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -85,8 +85,8 @@ public:
      */
     void ClientDisconnected(KServerSession* session);
 
-    std::shared_ptr<ServiceThread> GetServiceThread() const {
-        return service_thread.lock();
+    std::weak_ptr<ServiceThread> GetServiceThread() const {
+        return service_thread;
     }
 
 protected:
@@ -152,10 +152,12 @@ public:
         session_handler = std::move(handler);
     }
 
-    std::shared_ptr<ServiceThread> GetServiceThread() const {
+    std::weak_ptr<ServiceThread> GetServiceThread() const {
         return session_handler->GetServiceThread();
     }
 
+    bool HasSessionRequestHandler(const HLERequestContext& context) const;
+
 private:
     bool is_domain{};
     SessionRequestHandlerPtr session_handler;
@@ -163,7 +165,6 @@ private:
 
 private:
     KernelCore& kernel;
-    std::weak_ptr<ServiceThread> service_thread;
 };
 
 /**
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index 528ca8614..dd62706a8 100755
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -119,11 +119,16 @@ ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memor
 
     context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
 
-    if (auto strong_ptr = manager->GetServiceThread(); strong_ptr) {
-        strong_ptr->QueueSyncRequest(*parent, std::move(context));
-        return ResultSuccess;
+    // Ensure we have a session request handler
+    if (manager->HasSessionRequestHandler(*context)) {
+        if (auto strong_ptr = manager->GetServiceThread().lock()) {
+            strong_ptr->QueueSyncRequest(*parent, std::move(context));
+            return ResultSuccess;
+        } else {
+            ASSERT_MSG(false, "strong_ptr is nullptr!");
+        }
     } else {
-        ASSERT_MSG(false, "strong_ptr was nullptr!");
+        ASSERT_MSG(false, "handler is invalid!");
     }
 
     return ResultSuccess;
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 0ffb78d51..2ceeaeb5f 100755
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -63,8 +63,6 @@ struct KernelCore::Impl {
         global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
         global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
 
-        service_thread_manager =
-            std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager");
         is_phantom_mode_for_singlecore = false;
 
         InitializePhysicalCores();
@@ -96,7 +94,6 @@ struct KernelCore::Impl {
         process_list.clear();
 
         // Ensures all service threads gracefully shutdown
-        service_thread_manager.reset();
         service_threads.clear();
 
         next_object_id = 0;
@@ -680,10 +677,6 @@ struct KernelCore::Impl {
     // Threads used for services
     std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads;
 
-    // Service threads are managed by a worker thread, so that a calling service thread can queue up
-    // the release of itself
-    std::unique_ptr<Common::ThreadWorker> service_thread_manager;
-
     std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads;
     std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
     std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
@@ -986,17 +979,14 @@ void KernelCore::ExitSVCProfile() {
 
 std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) {
     auto service_thread = std::make_shared<Kernel::ServiceThread>(*this, 1, name);
-    impl->service_thread_manager->QueueWork(
-        [this, service_thread] { impl->service_threads.emplace(service_thread); });
+    impl->service_threads.emplace(service_thread);
     return service_thread;
 }
 
 void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
-    impl->service_thread_manager->QueueWork([this, service_thread] {
-        if (auto strong_ptr = service_thread.lock()) {
-            impl->service_threads.erase(strong_ptr);
-        }
-    });
+    if (auto strong_ptr = service_thread.lock()) {
+        impl->service_threads.erase(strong_ptr);
+    }
 }
 
 Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() {
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 9308cfef8..da956c99b 100755
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -505,6 +505,10 @@ void GameList::PopupContextMenu(const QPoint& menu_location) {
 void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::string& path) {
     QAction* favorite = context_menu.addAction(tr("Favorite"));
     context_menu.addSeparator();
+    QAction* start_game = context_menu.addAction(tr("Start Game"));
+    QAction* start_game_global =
+        context_menu.addAction(tr("Start Game without Custom Configuration"));
+    context_menu.addSeparator();
     QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location"));
     QAction* open_mod_location = context_menu.addAction(tr("Open Mod Data Location"));
     QAction* open_transferable_shader_cache =
@@ -540,6 +544,12 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
     connect(open_save_location, &QAction::triggered, [this, program_id, path]() {
         emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path);
     });
+    connect(start_game, &QAction::triggered, [this, path]() {
+        emit BootGame(QString::fromStdString(path), 0, StartGameType::Normal);
+    });
+    connect(start_game_global, &QAction::triggered, [this, path]() {
+        emit BootGame(QString::fromStdString(path), 0, StartGameType::Global);
+    });
     connect(open_mod_location, &QAction::triggered, [this, program_id, path]() {
         emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path);
     });
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index ab6866735..b630e34ff 100755
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -28,6 +28,7 @@ class GameListWorker;
 class GameListSearchField;
 class GameListDir;
 class GMainWindow;
+enum class StartGameType;
 
 namespace FileSys {
 class ManualContentProvider;
@@ -82,6 +83,7 @@ public:
     static const QStringList supported_file_extensions;
 
 signals:
+    void BootGame(const QString& game_path, std::size_t program_index, StartGameType type);
     void GameChosen(const QString& game_path);
     void ShouldCancelWorker();
     void OpenFolderRequested(u64 program_id, GameListOpenTarget target,
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index e683fb920..19339ff2d 100755
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1094,6 +1094,7 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
 }
 
 void GMainWindow::ConnectWidgetEvents() {
+    connect(game_list, &GameList::BootGame, this, &GMainWindow::BootGame);
     connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile);
     connect(game_list, &GameList::OpenDirectory, this, &GMainWindow::OnGameListOpenDirectory);
     connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder);
@@ -1320,7 +1321,7 @@ void GMainWindow::SelectAndSetCurrentUser() {
     Settings::values.current_user = dialog.GetIndex();
 }
 
-void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
+void GMainWindow::BootGame(const QString& filename, std::size_t program_index, StartGameType type) {
     LOG_INFO(Frontend, "yuzu starting...");
     StoreRecentFile(filename); // Put the filename on top of the list
 
@@ -1332,7 +1333,8 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
     const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData());
     const auto loader = Loader::GetLoader(system, v_file, program_index);
 
-    if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) {
+    if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success &&
+        type == StartGameType::Normal) {
         // Load per game settings
         const auto file_path = std::filesystem::path{filename.toStdU16String()};
         const auto config_file_name = title_id == 0
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 490b6889f..11f152cbe 100755
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -39,6 +39,11 @@ class GameListPlaceholder;
 
 class QtSoftwareKeyboardDialog;
 
+enum class StartGameType {
+    Normal, // Can use custom configuration
+    Global, // Only uses global configuration
+};
+
 namespace Core::Frontend {
 struct ControllerParameters;
 struct InlineAppearParameters;
@@ -181,7 +186,8 @@ private:
     void AllowOSSleep();
 
     bool LoadROM(const QString& filename, std::size_t program_index);
-    void BootGame(const QString& filename, std::size_t program_index = 0);
+    void BootGame(const QString& filename, std::size_t program_index = 0,
+                  StartGameType with_config = StartGameType::Normal);
     void ShutdownGame();
 
     void ShowTelemetryCallout();