Преглед изворни кода

am: Implement UserChannel parameters

Used by the Super Mairo 3D All-Stars collection.
FearlessTobi пре 2 година
родитељ
комит
87c0ba129c

+ 1 - 0
src/android/app/src/main/jni/native.cpp

@@ -270,6 +270,7 @@ public:
                                                        m_vulkan_library);
 
         m_system.SetFilesystem(m_vfs);
+        m_system.GetUserChannel().clear();
 
         // Initialize system.
         jauto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>();

+ 6 - 0
src/core/core.cpp

@@ -562,6 +562,8 @@ struct System::Impl {
 
     std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES>
         gpu_dirty_memory_write_manager{};
+
+    std::deque<std::vector<u8>> user_channel;
 };
 
 System::System() : impl{std::make_unique<Impl>(*this)} {}
@@ -1036,6 +1038,10 @@ void System::ExecuteProgram(std::size_t program_index) {
     }
 }
 
+std::deque<std::vector<u8>>& System::GetUserChannel() {
+    return impl->user_channel;
+}
+
 void System::RegisterExitCallback(ExitCallback&& callback) {
     impl->exit_callback = std::move(callback);
 }

+ 7 - 0
src/core/core.h

@@ -4,6 +4,7 @@
 #pragma once
 
 #include <cstddef>
+#include <deque>
 #include <functional>
 #include <memory>
 #include <mutex>
@@ -459,6 +460,12 @@ public:
      */
     void ExecuteProgram(std::size_t program_index);
 
+    /**
+     * Gets a reference to the user channel stack.
+     * It is used to transfer data between programs.
+     */
+    [[nodiscard]] std::deque<std::vector<u8>>& GetUserChannel();
+
     /// Type used for the frontend to designate a callback for System to exit the application.
     using ExitCallback = std::function<void()>;
 

+ 30 - 10
src/core/hle/service/am/am.cpp

@@ -1518,12 +1518,26 @@ void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto kind = rp.PopEnum<LaunchParameterKind>();
 
-    LOG_WARNING(Service_AM, "(STUBBED) called, kind={:08X}", kind);
+    LOG_INFO(Service_AM, "called, kind={:08X}", kind);
 
     if (kind == LaunchParameterKind::UserChannel) {
-        LOG_ERROR(Service_AM, "Popping from UserChannel is not supported!");
+        auto channel = system.GetUserChannel();
+        if (channel.empty()) {
+            LOG_ERROR(Service_AM, "Attempted to load launch parameter but none was found!");
+            IPC::ResponseBuilder rb{ctx, 2};
+            rb.Push(AM::ResultNoDataInChannel);
+            return;
+        }
+
+        auto data = channel.back();
+        channel.pop_back();
+
+        IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+        rb.Push(ResultSuccess);
+        rb.PushIpcInterface<IStorage>(system, std::move(data));
     } else if (kind == LaunchParameterKind::AccountPreselectedUser &&
                !launch_popped_account_preselect) {
+        // TODO: Verify this is hw-accurate
         LaunchParameterAccountPreselectedUser params{};
 
         params.magic = LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC;
@@ -1535,7 +1549,6 @@ void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) {
         params.current_user = *uuid;
 
         IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-
         rb.Push(ResultSuccess);
 
         std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser));
@@ -1543,12 +1556,11 @@ void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) {
 
         rb.PushIpcInterface<IStorage>(system, std::move(buffer));
         launch_popped_account_preselect = true;
-        return;
+    } else {
+        LOG_ERROR(Service_AM, "Unknown launch parameter kind.");
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(AM::ResultNoDataInChannel);
     }
-
-    LOG_ERROR(Service_AM, "Attempted to load launch parameter but none was found!");
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(AM::ResultNoDataInChannel);
 }
 
 void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx) {
@@ -1840,14 +1852,22 @@ void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) {
 }
 
 void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) {
-    LOG_WARNING(Service_AM, "(STUBBED) called");
+    LOG_DEBUG(Service_AM, "called");
+
+    system.GetUserChannel().clear();
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(ResultSuccess);
 }
 
 void IApplicationFunctions::UnpopToUserChannel(HLERequestContext& ctx) {
-    LOG_WARNING(Service_AM, "(STUBBED) called");
+    LOG_DEBUG(Service_AM, "called");
+
+    IPC::RequestParser rp{ctx};
+    const auto storage = rp.PopIpcInterface<IStorage>().lock();
+    if (storage) {
+        system.GetUserChannel().push_back(storage->GetData());
+    }
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(ResultSuccess);

+ 4 - 2
src/yuzu/game_list.cpp

@@ -588,10 +588,12 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
         emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path);
     });
     connect(start_game, &QAction::triggered, [this, path]() {
-        emit BootGame(QString::fromStdString(path), 0, 0, StartGameType::Normal);
+        emit BootGame(QString::fromStdString(path), 0, 0, StartGameType::Normal,
+                      AmLaunchType::UserInitiated);
     });
     connect(start_game_global, &QAction::triggered, [this, path]() {
-        emit BootGame(QString::fromStdString(path), 0, 0, StartGameType::Global);
+        emit BootGame(QString::fromStdString(path), 0, 0, StartGameType::Global,
+                      AmLaunchType::UserInitiated);
     });
     connect(open_mod_location, &QAction::triggered, [this, program_id, path]() {
         emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path);

+ 2 - 1
src/yuzu/game_list.h

@@ -28,6 +28,7 @@ class GameListWorker;
 class GameListSearchField;
 class GameListDir;
 class GMainWindow;
+enum class AmLaunchType;
 enum class StartGameType;
 
 namespace FileSys {
@@ -103,7 +104,7 @@ public:
 
 signals:
     void BootGame(const QString& game_path, u64 program_id, std::size_t program_index,
-                  StartGameType type);
+                  StartGameType type, AmLaunchType launch_type);
     void GameChosen(const QString& game_path, const u64 title_id = 0);
     void ShouldCancelWorker();
     void OpenFolderRequested(u64 program_id, GameListOpenTarget target,

+ 10 - 4
src/yuzu/main.cpp

@@ -1698,7 +1698,8 @@ void GMainWindow::AllowOSSleep() {
 #endif
 }
 
-bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t program_index) {
+bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t program_index,
+                          AmLaunchType launch_type) {
     // Shutdown previous session if the emu thread is still active...
     if (emu_thread != nullptr) {
         ShutdownGame();
@@ -1710,6 +1711,10 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
 
     system->SetFilesystem(vfs);
 
+    if (launch_type == AmLaunchType::UserInitiated) {
+        system->GetUserChannel().clear();
+    }
+
     system->SetAppletFrontendSet({
         std::make_unique<QtAmiiboSettings>(*this), // Amiibo Settings
         (UISettings::values.controller_applet_disabled.GetValue() == true)
@@ -1849,7 +1854,7 @@ void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) {
 }
 
 void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t program_index,
-                           StartGameType type) {
+                           StartGameType type, AmLaunchType launch_type) {
     LOG_INFO(Frontend, "yuzu starting...");
     StoreRecentFile(filename); // Put the filename on top of the list
 
@@ -1893,7 +1898,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
         }
     }
 
-    if (!LoadROM(filename, program_id, program_index)) {
+    if (!LoadROM(filename, program_id, program_index, launch_type)) {
         return;
     }
 
@@ -3314,7 +3319,8 @@ void GMainWindow::OnLoadComplete() {
 
 void GMainWindow::OnExecuteProgram(std::size_t program_index) {
     ShutdownGame();
-    BootGame(last_filename_booted, 0, program_index);
+    BootGame(last_filename_booted, 0, program_index, StartGameType::Normal,
+             AmLaunchType::ApplicationInitiated);
 }
 
 void GMainWindow::OnExit() {

+ 9 - 2
src/yuzu/main.h

@@ -58,6 +58,11 @@ enum class StartGameType {
     Global, // Only uses global configuration
 };
 
+enum class AmLaunchType {
+    UserInitiated,
+    ApplicationInitiated,
+};
+
 namespace Core {
 enum class SystemResultStatus : u32;
 class System;
@@ -239,9 +244,11 @@ private:
     void PreventOSSleep();
     void AllowOSSleep();
 
-    bool LoadROM(const QString& filename, u64 program_id, std::size_t program_index);
+    bool LoadROM(const QString& filename, u64 program_id, std::size_t program_index,
+                 AmLaunchType launch_type);
     void BootGame(const QString& filename, u64 program_id = 0, std::size_t program_index = 0,
-                  StartGameType with_config = StartGameType::Normal);
+                  StartGameType with_config = StartGameType::Normal,
+                  AmLaunchType launch_type = AmLaunchType::UserInitiated);
     void ShutdownGame();
 
     void ShowTelemetryCallout();

+ 1 - 0
src/yuzu_cmd/yuzu.cpp

@@ -358,6 +358,7 @@ int main(int argc, char** argv) {
     system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
     system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
     system.GetFileSystemController().CreateFactories(*system.GetFilesystem());
+    system.GetUserChannel().clear();
 
     const Core::SystemResultStatus load_result{system.Load(*emu_window, filepath)};