diff options
| author | 2020-11-24 15:27:22 -0800 | |
|---|---|---|
| committer | 2020-11-24 15:27:22 -0800 | |
| commit | 0832da3e4054d0b47c39e95553b5f3be5848eae9 (patch) | |
| tree | 1e7688670225c60bbcbc2827cf427a67e1686404 /src | |
| parent | hle: services: Fix a crash with improper NVFlinger lifetime management. (#4977) (diff) | |
| parent | frontend: yuzu (qt): Register a callback for ExecuteProgram. (diff) | |
| download | yuzu-0832da3e4054d0b47c39e95553b5f3be5848eae9.tar.gz yuzu-0832da3e4054d0b47c39e95553b5f3be5848eae9.tar.xz yuzu-0832da3e4054d0b47c39e95553b5f3be5848eae9.zip | |
Merge pull request #4799 from bunnei/execute-program
core: Refactor loader and implement ExecuteProgram
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/core.cpp | 29 | ||||
| -rw-r--r-- | src/core/core.h | 22 | ||||
| -rw-r--r-- | src/core/file_sys/card_image.cpp | 5 | ||||
| -rw-r--r-- | src/core/file_sys/card_image.h | 2 | ||||
| -rw-r--r-- | src/core/file_sys/submission_package.cpp | 6 | ||||
| -rw-r--r-- | src/core/file_sys/submission_package.h | 4 | ||||
| -rw-r--r-- | src/core/hle/service/am/am.cpp | 34 | ||||
| -rw-r--r-- | src/core/hle/service/am/am.h | 3 | ||||
| -rw-r--r-- | src/core/loader/loader.cpp | 12 | ||||
| -rw-r--r-- | src/core/loader/loader.h | 4 | ||||
| -rw-r--r-- | src/core/loader/nsp.cpp | 5 | ||||
| -rw-r--r-- | src/core/loader/nsp.h | 3 | ||||
| -rw-r--r-- | src/core/loader/xci.cpp | 5 | ||||
| -rw-r--r-- | src/core/loader/xci.h | 3 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.cpp | 6 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.h | 7 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 24 | ||||
| -rw-r--r-- | src/yuzu/main.h | 8 |
18 files changed, 146 insertions, 36 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index 1aa477a29..7ca3652af 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -145,7 +145,7 @@ struct System::Impl { | |||
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { | 147 | ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { |
| 148 | LOG_DEBUG(HW_Memory, "initialized OK"); | 148 | LOG_DEBUG(Core, "initialized OK"); |
| 149 | 149 | ||
| 150 | device_memory = std::make_unique<Core::DeviceMemory>(); | 150 | device_memory = std::make_unique<Core::DeviceMemory>(); |
| 151 | 151 | ||
| @@ -208,9 +208,11 @@ struct System::Impl { | |||
| 208 | return ResultStatus::Success; | 208 | return ResultStatus::Success; |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, | 211 | ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath, |
| 212 | const std::string& filepath) { | 212 | std::size_t program_index) { |
| 213 | app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath)); | 213 | app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath), |
| 214 | program_index); | ||
| 215 | |||
| 214 | if (!app_loader) { | 216 | if (!app_loader) { |
| 215 | LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); | 217 | LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); |
| 216 | return ResultStatus::ErrorGetLoader; | 218 | return ResultStatus::ErrorGetLoader; |
| @@ -416,6 +418,8 @@ struct System::Impl { | |||
| 416 | bool is_multicore{}; | 418 | bool is_multicore{}; |
| 417 | bool is_async_gpu{}; | 419 | bool is_async_gpu{}; |
| 418 | 420 | ||
| 421 | ExecuteProgramCallback execute_program_callback; | ||
| 422 | |||
| 419 | std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; | 423 | std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; |
| 420 | std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{}; | 424 | std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{}; |
| 421 | }; | 425 | }; |
| @@ -451,8 +455,9 @@ void System::Shutdown() { | |||
| 451 | impl->Shutdown(); | 455 | impl->Shutdown(); |
| 452 | } | 456 | } |
| 453 | 457 | ||
| 454 | System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { | 458 | System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath, |
| 455 | return impl->Load(*this, emu_window, filepath); | 459 | std::size_t program_index) { |
| 460 | return impl->Load(*this, emu_window, filepath, program_index); | ||
| 456 | } | 461 | } |
| 457 | 462 | ||
| 458 | bool System::IsPoweredOn() const { | 463 | bool System::IsPoweredOn() const { |
| @@ -789,4 +794,16 @@ bool System::IsMulticore() const { | |||
| 789 | return impl->is_multicore; | 794 | return impl->is_multicore; |
| 790 | } | 795 | } |
| 791 | 796 | ||
| 797 | void System::RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback) { | ||
| 798 | impl->execute_program_callback = std::move(callback); | ||
| 799 | } | ||
| 800 | |||
| 801 | void System::ExecuteProgram(std::size_t program_index) { | ||
| 802 | if (impl->execute_program_callback) { | ||
| 803 | impl->execute_program_callback(program_index); | ||
| 804 | } else { | ||
| 805 | LOG_CRITICAL(Core, "execute_program_callback must be initialized by the frontend"); | ||
| 806 | } | ||
| 807 | } | ||
| 808 | |||
| 792 | } // namespace Core | 809 | } // namespace Core |
diff --git a/src/core/core.h b/src/core/core.h index cd155625c..f642befc0 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | 7 | #include <cstddef> |
| 8 | #include <functional> | ||
| 8 | #include <memory> | 9 | #include <memory> |
| 9 | #include <string> | 10 | #include <string> |
| 10 | #include <vector> | 11 | #include <vector> |
| @@ -173,9 +174,11 @@ public: | |||
| 173 | * @param emu_window Reference to the host-system window used for video output and keyboard | 174 | * @param emu_window Reference to the host-system window used for video output and keyboard |
| 174 | * input. | 175 | * input. |
| 175 | * @param filepath String path to the executable application to load on the host file system. | 176 | * @param filepath String path to the executable application to load on the host file system. |
| 177 | * @param program_index Specifies the index within the container of the program to launch. | ||
| 176 | * @returns ResultStatus code, indicating if the operation succeeded. | 178 | * @returns ResultStatus code, indicating if the operation succeeded. |
| 177 | */ | 179 | */ |
| 178 | [[nodiscard]] ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath); | 180 | [[nodiscard]] ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath, |
| 181 | std::size_t program_index = 0); | ||
| 179 | 182 | ||
| 180 | /** | 183 | /** |
| 181 | * Indicates if the emulated system is powered on (all subsystems initialized and able to run an | 184 | * Indicates if the emulated system is powered on (all subsystems initialized and able to run an |
| @@ -385,6 +388,23 @@ public: | |||
| 385 | /// Tells if system is running on multicore. | 388 | /// Tells if system is running on multicore. |
| 386 | [[nodiscard]] bool IsMulticore() const; | 389 | [[nodiscard]] bool IsMulticore() const; |
| 387 | 390 | ||
| 391 | /// Type used for the frontend to designate a callback for System to re-launch the application | ||
| 392 | /// using a specified program index. | ||
| 393 | using ExecuteProgramCallback = std::function<void(std::size_t)>; | ||
| 394 | |||
| 395 | /** | ||
| 396 | * Registers a callback from the frontend for System to re-launch the application using a | ||
| 397 | * specified program index. | ||
| 398 | * @param callback Callback from the frontend to relaunch the application. | ||
| 399 | */ | ||
| 400 | void RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback); | ||
| 401 | |||
| 402 | /** | ||
| 403 | * Instructs the frontend to re-launch the application using the specified program_index. | ||
| 404 | * @param program_index Specifies the index within the application of the program to launch. | ||
| 405 | */ | ||
| 406 | void ExecuteProgram(std::size_t program_index); | ||
| 407 | |||
| 388 | private: | 408 | private: |
| 389 | System(); | 409 | System(); |
| 390 | 410 | ||
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index 956da68f7..8dee5590b 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp | |||
| @@ -29,7 +29,7 @@ constexpr std::array partition_names{ | |||
| 29 | "logo", | 29 | "logo", |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | XCI::XCI(VirtualFile file_) | 32 | XCI::XCI(VirtualFile file_, std::size_t program_index) |
| 33 | : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA}, | 33 | : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA}, |
| 34 | partitions(partition_names.size()), | 34 | partitions(partition_names.size()), |
| 35 | partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} { | 35 | partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} { |
| @@ -62,7 +62,8 @@ XCI::XCI(VirtualFile file_) | |||
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | secure_partition = std::make_shared<NSP>( | 64 | secure_partition = std::make_shared<NSP>( |
| 65 | main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)])); | 65 | main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]), |
| 66 | program_index); | ||
| 66 | 67 | ||
| 67 | ncas = secure_partition->GetNCAsCollapsed(); | 68 | ncas = secure_partition->GetNCAsCollapsed(); |
| 68 | program = | 69 | program = |
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h index 2d0a0f285..4960e90fe 100644 --- a/src/core/file_sys/card_image.h +++ b/src/core/file_sys/card_image.h | |||
| @@ -78,7 +78,7 @@ enum class XCIPartition : u8 { Update, Normal, Secure, Logo }; | |||
| 78 | 78 | ||
| 79 | class XCI : public ReadOnlyVfsDirectory { | 79 | class XCI : public ReadOnlyVfsDirectory { |
| 80 | public: | 80 | public: |
| 81 | explicit XCI(VirtualFile file); | 81 | explicit XCI(VirtualFile file, std::size_t program_index = 0); |
| 82 | ~XCI() override; | 82 | ~XCI() override; |
| 83 | 83 | ||
| 84 | Loader::ResultStatus GetStatus() const; | 84 | Loader::ResultStatus GetStatus() const; |
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp index 90641d23b..c05735ddd 100644 --- a/src/core/file_sys/submission_package.cpp +++ b/src/core/file_sys/submission_package.cpp | |||
| @@ -20,8 +20,8 @@ | |||
| 20 | 20 | ||
| 21 | namespace FileSys { | 21 | namespace FileSys { |
| 22 | 22 | ||
| 23 | NSP::NSP(VirtualFile file_) | 23 | NSP::NSP(VirtualFile file_, std::size_t program_index) |
| 24 | : file(std::move(file_)), status{Loader::ResultStatus::Success}, | 24 | : file(std::move(file_)), program_index(program_index), status{Loader::ResultStatus::Success}, |
| 25 | pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} { | 25 | pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} { |
| 26 | if (pfs->GetStatus() != Loader::ResultStatus::Success) { | 26 | if (pfs->GetStatus() != Loader::ResultStatus::Success) { |
| 27 | status = pfs->GetStatus(); | 27 | status = pfs->GetStatus(); |
| @@ -146,7 +146,7 @@ std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type, TitleType | |||
| 146 | if (extracted) | 146 | if (extracted) |
| 147 | LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); | 147 | LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); |
| 148 | 148 | ||
| 149 | const auto title_id_iter = ncas.find(title_id); | 149 | const auto title_id_iter = ncas.find(title_id + program_index); |
| 150 | if (title_id_iter == ncas.end()) | 150 | if (title_id_iter == ncas.end()) |
| 151 | return nullptr; | 151 | return nullptr; |
| 152 | 152 | ||
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h index c70a11b5b..54581a6f3 100644 --- a/src/core/file_sys/submission_package.h +++ b/src/core/file_sys/submission_package.h | |||
| @@ -27,7 +27,7 @@ enum class ContentRecordType : u8; | |||
| 27 | 27 | ||
| 28 | class NSP : public ReadOnlyVfsDirectory { | 28 | class NSP : public ReadOnlyVfsDirectory { |
| 29 | public: | 29 | public: |
| 30 | explicit NSP(VirtualFile file); | 30 | explicit NSP(VirtualFile file, std::size_t program_index = 0); |
| 31 | ~NSP() override; | 31 | ~NSP() override; |
| 32 | 32 | ||
| 33 | Loader::ResultStatus GetStatus() const; | 33 | Loader::ResultStatus GetStatus() const; |
| @@ -69,6 +69,8 @@ private: | |||
| 69 | 69 | ||
| 70 | VirtualFile file; | 70 | VirtualFile file; |
| 71 | 71 | ||
| 72 | const std::size_t program_index; | ||
| 73 | |||
| 72 | bool extracted = false; | 74 | bool extracted = false; |
| 73 | Loader::ResultStatus status; | 75 | Loader::ResultStatus status; |
| 74 | std::map<u64, Loader::ResultStatus> program_status; | 76 | std::map<u64, Loader::ResultStatus> program_status; |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 55e428456..703a9b234 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -1188,9 +1188,9 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) | |||
| 1188 | {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"}, | 1188 | {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"}, |
| 1189 | {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"}, | 1189 | {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"}, |
| 1190 | {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"}, | 1190 | {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"}, |
| 1191 | {120, nullptr, "ExecuteProgram"}, | 1191 | {120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"}, |
| 1192 | {121, nullptr, "ClearUserChannel"}, | 1192 | {121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"}, |
| 1193 | {122, nullptr, "UnpopToUserChannel"}, | 1193 | {122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"}, |
| 1194 | {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"}, | 1194 | {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"}, |
| 1195 | {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, | 1195 | {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, |
| 1196 | {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, | 1196 | {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, |
| @@ -1561,6 +1561,34 @@ void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLEReque | |||
| 1561 | rb.Push<u32>(0); | 1561 | rb.Push<u32>(0); |
| 1562 | } | 1562 | } |
| 1563 | 1563 | ||
| 1564 | void IApplicationFunctions::ExecuteProgram(Kernel::HLERequestContext& ctx) { | ||
| 1565 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1566 | |||
| 1567 | IPC::RequestParser rp{ctx}; | ||
| 1568 | [[maybe_unused]] const auto unk_1 = rp.Pop<u32>(); | ||
| 1569 | [[maybe_unused]] const auto unk_2 = rp.Pop<u32>(); | ||
| 1570 | const auto program_index = rp.Pop<u64>(); | ||
| 1571 | |||
| 1572 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1573 | rb.Push(RESULT_SUCCESS); | ||
| 1574 | |||
| 1575 | system.ExecuteProgram(program_index); | ||
| 1576 | } | ||
| 1577 | |||
| 1578 | void IApplicationFunctions::ClearUserChannel(Kernel::HLERequestContext& ctx) { | ||
| 1579 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1580 | |||
| 1581 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1582 | rb.Push(RESULT_SUCCESS); | ||
| 1583 | } | ||
| 1584 | |||
| 1585 | void IApplicationFunctions::UnpopToUserChannel(Kernel::HLERequestContext& ctx) { | ||
| 1586 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1587 | |||
| 1588 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1589 | rb.Push(RESULT_SUCCESS); | ||
| 1590 | } | ||
| 1591 | |||
| 1564 | void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) { | 1592 | void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) { |
| 1565 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 1593 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 1566 | 1594 | ||
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 09c2d05bc..af97c303a 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -287,6 +287,9 @@ private: | |||
| 287 | void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx); | 287 | void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx); |
| 288 | void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx); | 288 | void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx); |
| 289 | void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx); | 289 | void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx); |
| 290 | void ExecuteProgram(Kernel::HLERequestContext& ctx); | ||
| 291 | void ClearUserChannel(Kernel::HLERequestContext& ctx); | ||
| 292 | void UnpopToUserChannel(Kernel::HLERequestContext& ctx); | ||
| 290 | void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx); | 293 | void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx); |
| 291 | void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); | 294 | void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); |
| 292 | void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx); | 295 | void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx); |
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index deffe7379..d91c15561 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -198,10 +198,11 @@ AppLoader::~AppLoader() = default; | |||
| 198 | * @param system The system context to use. | 198 | * @param system The system context to use. |
| 199 | * @param file The file to retrieve the loader for | 199 | * @param file The file to retrieve the loader for |
| 200 | * @param type The file type | 200 | * @param type The file type |
| 201 | * @param program_index Specifies the index within the container of the program to launch. | ||
| 201 | * @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type | 202 | * @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type |
| 202 | */ | 203 | */ |
| 203 | static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file, | 204 | static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file, |
| 204 | FileType type) { | 205 | FileType type, std::size_t program_index) { |
| 205 | switch (type) { | 206 | switch (type) { |
| 206 | // Standard ELF file format. | 207 | // Standard ELF file format. |
| 207 | case FileType::ELF: | 208 | case FileType::ELF: |
| @@ -222,7 +223,7 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V | |||
| 222 | // NX XCI (nX Card Image) file format. | 223 | // NX XCI (nX Card Image) file format. |
| 223 | case FileType::XCI: | 224 | case FileType::XCI: |
| 224 | return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(), | 225 | return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(), |
| 225 | system.GetContentProvider()); | 226 | system.GetContentProvider(), program_index); |
| 226 | 227 | ||
| 227 | // NX NAX (NintendoAesXts) file format. | 228 | // NX NAX (NintendoAesXts) file format. |
| 228 | case FileType::NAX: | 229 | case FileType::NAX: |
| @@ -231,7 +232,7 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V | |||
| 231 | // NX NSP (Nintendo Submission Package) file format | 232 | // NX NSP (Nintendo Submission Package) file format |
| 232 | case FileType::NSP: | 233 | case FileType::NSP: |
| 233 | return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(), | 234 | return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(), |
| 234 | system.GetContentProvider()); | 235 | system.GetContentProvider(), program_index); |
| 235 | 236 | ||
| 236 | // NX KIP (Kernel Internal Process) file format | 237 | // NX KIP (Kernel Internal Process) file format |
| 237 | case FileType::KIP: | 238 | case FileType::KIP: |
| @@ -246,7 +247,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V | |||
| 246 | } | 247 | } |
| 247 | } | 248 | } |
| 248 | 249 | ||
| 249 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file) { | 250 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, |
| 251 | std::size_t program_index) { | ||
| 250 | FileType type = IdentifyFile(file); | 252 | FileType type = IdentifyFile(file); |
| 251 | const FileType filename_type = GuessFromFilename(file->GetName()); | 253 | const FileType filename_type = GuessFromFilename(file->GetName()); |
| 252 | 254 | ||
| @@ -260,7 +262,7 @@ std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile | |||
| 260 | 262 | ||
| 261 | LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type)); | 263 | LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type)); |
| 262 | 264 | ||
| 263 | return GetFileLoader(system, std::move(file), type); | 265 | return GetFileLoader(system, std::move(file), type, program_index); |
| 264 | } | 266 | } |
| 265 | 267 | ||
| 266 | } // namespace Loader | 268 | } // namespace Loader |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 8dc2d7615..36e79e71d 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -293,9 +293,11 @@ protected: | |||
| 293 | * | 293 | * |
| 294 | * @param system The system context. | 294 | * @param system The system context. |
| 295 | * @param file The bootable file. | 295 | * @param file The bootable file. |
| 296 | * @param program_index Specifies the index within the container of the program to launch. | ||
| 296 | * | 297 | * |
| 297 | * @return the best loader for this file. | 298 | * @return the best loader for this file. |
| 298 | */ | 299 | */ |
| 299 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file); | 300 | std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, |
| 301 | std::size_t program_index = 0); | ||
| 300 | 302 | ||
| 301 | } // namespace Loader | 303 | } // namespace Loader |
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index e821937fd..928f64c8c 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp | |||
| @@ -23,8 +23,9 @@ namespace Loader { | |||
| 23 | 23 | ||
| 24 | AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file, | 24 | AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file, |
| 25 | const Service::FileSystem::FileSystemController& fsc, | 25 | const Service::FileSystem::FileSystemController& fsc, |
| 26 | const FileSys::ContentProvider& content_provider) | 26 | const FileSys::ContentProvider& content_provider, |
| 27 | : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file)), | 27 | std::size_t program_index) |
| 28 | : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file, program_index)), | ||
| 28 | title_id(nsp->GetProgramTitleID()) { | 29 | title_id(nsp->GetProgramTitleID()) { |
| 29 | 30 | ||
| 30 | if (nsp->GetStatus() != ResultStatus::Success) { | 31 | if (nsp->GetStatus() != ResultStatus::Success) { |
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h index 36e8e3533..f0518ac47 100644 --- a/src/core/loader/nsp.h +++ b/src/core/loader/nsp.h | |||
| @@ -28,7 +28,8 @@ class AppLoader_NSP final : public AppLoader { | |||
| 28 | public: | 28 | public: |
| 29 | explicit AppLoader_NSP(FileSys::VirtualFile file, | 29 | explicit AppLoader_NSP(FileSys::VirtualFile file, |
| 30 | const Service::FileSystem::FileSystemController& fsc, | 30 | const Service::FileSystem::FileSystemController& fsc, |
| 31 | const FileSys::ContentProvider& content_provider); | 31 | const FileSys::ContentProvider& content_provider, |
| 32 | std::size_t program_index); | ||
| 32 | ~AppLoader_NSP() override; | 33 | ~AppLoader_NSP() override; |
| 33 | 34 | ||
| 34 | /** | 35 | /** |
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 536e721fc..aaa250cea 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp | |||
| @@ -22,8 +22,9 @@ namespace Loader { | |||
| 22 | 22 | ||
| 23 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file, | 23 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file, |
| 24 | const Service::FileSystem::FileSystemController& fsc, | 24 | const Service::FileSystem::FileSystemController& fsc, |
| 25 | const FileSys::ContentProvider& content_provider) | 25 | const FileSys::ContentProvider& content_provider, |
| 26 | : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)), | 26 | std::size_t program_index) |
| 27 | : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file, program_index)), | ||
| 27 | nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) { | 28 | nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) { |
| 28 | if (xci->GetStatus() != ResultStatus::Success) { | 29 | if (xci->GetStatus() != ResultStatus::Success) { |
| 29 | return; | 30 | return; |
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index 6dc1f9243..764dc8328 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h | |||
| @@ -28,7 +28,8 @@ class AppLoader_XCI final : public AppLoader { | |||
| 28 | public: | 28 | public: |
| 29 | explicit AppLoader_XCI(FileSys::VirtualFile file, | 29 | explicit AppLoader_XCI(FileSys::VirtualFile file, |
| 30 | const Service::FileSystem::FileSystemController& fsc, | 30 | const Service::FileSystem::FileSystemController& fsc, |
| 31 | const FileSys::ContentProvider& content_provider); | 31 | const FileSys::ContentProvider& content_provider, |
| 32 | std::size_t program_index); | ||
| 32 | ~AppLoader_XCI() override; | 33 | ~AppLoader_XCI() override; |
| 33 | 34 | ||
| 34 | /** | 35 | /** |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index d62b0efc2..f0338cf7a 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -302,6 +302,12 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, | |||
| 302 | this->setMouseTracking(true); | 302 | this->setMouseTracking(true); |
| 303 | 303 | ||
| 304 | connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); | 304 | connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); |
| 305 | connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram, | ||
| 306 | Qt::QueuedConnection); | ||
| 307 | } | ||
| 308 | |||
| 309 | void GRenderWindow::ExecuteProgram(std::size_t program_index) { | ||
| 310 | emit ExecuteProgramSignal(program_index); | ||
| 305 | } | 311 | } |
| 306 | 312 | ||
| 307 | GRenderWindow::~GRenderWindow() { | 313 | GRenderWindow::~GRenderWindow() { |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index ca35cf831..503b4f89e 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -166,6 +166,12 @@ public: | |||
| 166 | 166 | ||
| 167 | std::pair<u32, u32> ScaleTouch(const QPointF& pos) const; | 167 | std::pair<u32, u32> ScaleTouch(const QPointF& pos) const; |
| 168 | 168 | ||
| 169 | /** | ||
| 170 | * Instructs the window to re-launch the application using the specified program_index. | ||
| 171 | * @param program_index Specifies the index within the application of the program to launch. | ||
| 172 | */ | ||
| 173 | void ExecuteProgram(std::size_t program_index); | ||
| 174 | |||
| 169 | public slots: | 175 | public slots: |
| 170 | void OnEmulationStarting(EmuThread* emu_thread); | 176 | void OnEmulationStarting(EmuThread* emu_thread); |
| 171 | void OnEmulationStopping(); | 177 | void OnEmulationStopping(); |
| @@ -175,6 +181,7 @@ signals: | |||
| 175 | /// Emitted when the window is closed | 181 | /// Emitted when the window is closed |
| 176 | void Closed(); | 182 | void Closed(); |
| 177 | void FirstFrameDisplayed(); | 183 | void FirstFrameDisplayed(); |
| 184 | void ExecuteProgramSignal(std::size_t program_index); | ||
| 178 | 185 | ||
| 179 | private: | 186 | private: |
| 180 | void TouchBeginEvent(const QTouchEvent* event); | 187 | void TouchBeginEvent(const QTouchEvent* event); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e704cc656..805619ccf 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -978,7 +978,7 @@ void GMainWindow::AllowOSSleep() { | |||
| 978 | #endif | 978 | #endif |
| 979 | } | 979 | } |
| 980 | 980 | ||
| 981 | bool GMainWindow::LoadROM(const QString& filename) { | 981 | bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) { |
| 982 | // Shutdown previous session if the emu thread is still active... | 982 | // Shutdown previous session if the emu thread is still active... |
| 983 | if (emu_thread != nullptr) | 983 | if (emu_thread != nullptr) |
| 984 | ShutdownGame(); | 984 | ShutdownGame(); |
| @@ -1003,7 +1003,8 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
| 1003 | 1003 | ||
| 1004 | system.RegisterHostThread(); | 1004 | system.RegisterHostThread(); |
| 1005 | 1005 | ||
| 1006 | const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; | 1006 | const Core::System::ResultStatus result{ |
| 1007 | system.Load(*render_window, filename.toStdString(), program_index)}; | ||
| 1007 | 1008 | ||
| 1008 | const auto drd_callout = | 1009 | const auto drd_callout = |
| 1009 | (UISettings::values.callout_flags & static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0; | 1010 | (UISettings::values.callout_flags & static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0; |
| @@ -1085,14 +1086,18 @@ void GMainWindow::SelectAndSetCurrentUser() { | |||
| 1085 | Settings::values.current_user = dialog.GetIndex(); | 1086 | Settings::values.current_user = dialog.GetIndex(); |
| 1086 | } | 1087 | } |
| 1087 | 1088 | ||
| 1088 | void GMainWindow::BootGame(const QString& filename) { | 1089 | void GMainWindow::BootGame(const QString& filename, std::size_t program_index) { |
| 1089 | LOG_INFO(Frontend, "yuzu starting..."); | 1090 | LOG_INFO(Frontend, "yuzu starting..."); |
| 1090 | StoreRecentFile(filename); // Put the filename on top of the list | 1091 | StoreRecentFile(filename); // Put the filename on top of the list |
| 1091 | 1092 | ||
| 1092 | u64 title_id{0}; | 1093 | u64 title_id{0}; |
| 1094 | |||
| 1095 | last_filename_booted = filename; | ||
| 1096 | |||
| 1093 | auto& system = Core::System::GetInstance(); | 1097 | auto& system = Core::System::GetInstance(); |
| 1094 | const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); | 1098 | const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); |
| 1095 | const auto loader = Loader::GetLoader(system, v_file); | 1099 | const auto loader = Loader::GetLoader(system, v_file, program_index); |
| 1100 | |||
| 1096 | if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) { | 1101 | if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) { |
| 1097 | // Load per game settings | 1102 | // Load per game settings |
| 1098 | Config per_game_config(fmt::format("{:016X}", title_id), Config::ConfigType::PerGameConfig); | 1103 | Config per_game_config(fmt::format("{:016X}", title_id), Config::ConfigType::PerGameConfig); |
| @@ -1106,7 +1111,7 @@ void GMainWindow::BootGame(const QString& filename) { | |||
| 1106 | SelectAndSetCurrentUser(); | 1111 | SelectAndSetCurrentUser(); |
| 1107 | } | 1112 | } |
| 1108 | 1113 | ||
| 1109 | if (!LoadROM(filename)) | 1114 | if (!LoadROM(filename, program_index)) |
| 1110 | return; | 1115 | return; |
| 1111 | 1116 | ||
| 1112 | // Create and start the emulation thread | 1117 | // Create and start the emulation thread |
| @@ -1114,6 +1119,10 @@ void GMainWindow::BootGame(const QString& filename) { | |||
| 1114 | emit EmulationStarting(emu_thread.get()); | 1119 | emit EmulationStarting(emu_thread.get()); |
| 1115 | emu_thread->start(); | 1120 | emu_thread->start(); |
| 1116 | 1121 | ||
| 1122 | // Register an ExecuteProgram callback such that Core can execute a sub-program | ||
| 1123 | system.RegisterExecuteProgramCallback( | ||
| 1124 | [this](std::size_t program_index) { render_window->ExecuteProgram(program_index); }); | ||
| 1125 | |||
| 1117 | connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); | 1126 | connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); |
| 1118 | // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views | 1127 | // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views |
| 1119 | // before the CPU continues | 1128 | // before the CPU continues |
| @@ -2136,6 +2145,11 @@ void GMainWindow::OnLoadComplete() { | |||
| 2136 | loading_screen->OnLoadComplete(); | 2145 | loading_screen->OnLoadComplete(); |
| 2137 | } | 2146 | } |
| 2138 | 2147 | ||
| 2148 | void GMainWindow::OnExecuteProgram(std::size_t program_index) { | ||
| 2149 | ShutdownGame(); | ||
| 2150 | BootGame(last_filename_booted, program_index); | ||
| 2151 | } | ||
| 2152 | |||
| 2139 | void GMainWindow::ErrorDisplayDisplayError(QString body) { | 2153 | void GMainWindow::ErrorDisplayDisplayError(QString body) { |
| 2140 | QMessageBox::critical(this, tr("Error Display"), body); | 2154 | QMessageBox::critical(this, tr("Error Display"), body); |
| 2141 | emit ErrorDisplayFinished(); | 2155 | emit ErrorDisplayFinished(); |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index b380a66f3..6242341d1 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -131,6 +131,7 @@ signals: | |||
| 131 | 131 | ||
| 132 | public slots: | 132 | public slots: |
| 133 | void OnLoadComplete(); | 133 | void OnLoadComplete(); |
| 134 | void OnExecuteProgram(std::size_t program_index); | ||
| 134 | void ControllerSelectorReconfigureControllers( | 135 | void ControllerSelectorReconfigureControllers( |
| 135 | const Core::Frontend::ControllerParameters& parameters); | 136 | const Core::Frontend::ControllerParameters& parameters); |
| 136 | void ErrorDisplayDisplayError(QString body); | 137 | void ErrorDisplayDisplayError(QString body); |
| @@ -154,8 +155,8 @@ private: | |||
| 154 | void PreventOSSleep(); | 155 | void PreventOSSleep(); |
| 155 | void AllowOSSleep(); | 156 | void AllowOSSleep(); |
| 156 | 157 | ||
| 157 | bool LoadROM(const QString& filename); | 158 | bool LoadROM(const QString& filename, std::size_t program_index); |
| 158 | void BootGame(const QString& filename); | 159 | void BootGame(const QString& filename, std::size_t program_index = 0); |
| 159 | void ShutdownGame(); | 160 | void ShutdownGame(); |
| 160 | 161 | ||
| 161 | void ShowTelemetryCallout(); | 162 | void ShowTelemetryCallout(); |
| @@ -317,6 +318,9 @@ private: | |||
| 317 | // Install progress dialog | 318 | // Install progress dialog |
| 318 | QProgressDialog* install_progress; | 319 | QProgressDialog* install_progress; |
| 319 | 320 | ||
| 321 | // Last game booted, used for multi-process apps | ||
| 322 | QString last_filename_booted; | ||
| 323 | |||
| 320 | protected: | 324 | protected: |
| 321 | void dropEvent(QDropEvent* event) override; | 325 | void dropEvent(QDropEvent* event) override; |
| 322 | void dragEnterEvent(QDragEnterEvent* event) override; | 326 | void dragEnterEvent(QDragEnterEvent* event) override; |