Merge pull request #4799 from bunnei/execute-program
core: Refactor loader and implement ExecuteProgram
This commit is contained in:
commit
0832da3e40
@ -145,7 +145,7 @@ struct System::Impl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
|
ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
|
||||||
LOG_DEBUG(HW_Memory, "initialized OK");
|
LOG_DEBUG(Core, "initialized OK");
|
||||||
|
|
||||||
device_memory = std::make_unique<Core::DeviceMemory>();
|
device_memory = std::make_unique<Core::DeviceMemory>();
|
||||||
|
|
||||||
@ -208,9 +208,11 @@ struct System::Impl {
|
|||||||
return ResultStatus::Success;
|
return ResultStatus::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
|
ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath,
|
||||||
const std::string& filepath) {
|
std::size_t program_index) {
|
||||||
app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath));
|
app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath),
|
||||||
|
program_index);
|
||||||
|
|
||||||
if (!app_loader) {
|
if (!app_loader) {
|
||||||
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
|
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
|
||||||
return ResultStatus::ErrorGetLoader;
|
return ResultStatus::ErrorGetLoader;
|
||||||
@ -416,6 +418,8 @@ struct System::Impl {
|
|||||||
bool is_multicore{};
|
bool is_multicore{};
|
||||||
bool is_async_gpu{};
|
bool is_async_gpu{};
|
||||||
|
|
||||||
|
ExecuteProgramCallback execute_program_callback;
|
||||||
|
|
||||||
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
|
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
|
||||||
std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{};
|
std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{};
|
||||||
};
|
};
|
||||||
@ -451,8 +455,9 @@ void System::Shutdown() {
|
|||||||
impl->Shutdown();
|
impl->Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
|
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
|
||||||
return impl->Load(*this, emu_window, filepath);
|
std::size_t program_index) {
|
||||||
|
return impl->Load(*this, emu_window, filepath, program_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool System::IsPoweredOn() const {
|
bool System::IsPoweredOn() const {
|
||||||
@ -789,4 +794,16 @@ bool System::IsMulticore() const {
|
|||||||
return impl->is_multicore;
|
return impl->is_multicore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void System::RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback) {
|
||||||
|
impl->execute_program_callback = std::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void System::ExecuteProgram(std::size_t program_index) {
|
||||||
|
if (impl->execute_program_callback) {
|
||||||
|
impl->execute_program_callback(program_index);
|
||||||
|
} else {
|
||||||
|
LOG_CRITICAL(Core, "execute_program_callback must be initialized by the frontend");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -173,9 +174,11 @@ public:
|
|||||||
* @param emu_window Reference to the host-system window used for video output and keyboard
|
* @param emu_window Reference to the host-system window used for video output and keyboard
|
||||||
* input.
|
* input.
|
||||||
* @param filepath String path to the executable application to load on the host file system.
|
* @param filepath String path to the executable application to load on the host file system.
|
||||||
|
* @param program_index Specifies the index within the container of the program to launch.
|
||||||
* @returns ResultStatus code, indicating if the operation succeeded.
|
* @returns ResultStatus code, indicating if the operation succeeded.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath);
|
[[nodiscard]] ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
|
||||||
|
std::size_t program_index = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates if the emulated system is powered on (all subsystems initialized and able to run an
|
* Indicates if the emulated system is powered on (all subsystems initialized and able to run an
|
||||||
@ -385,6 +388,23 @@ public:
|
|||||||
/// Tells if system is running on multicore.
|
/// Tells if system is running on multicore.
|
||||||
[[nodiscard]] bool IsMulticore() const;
|
[[nodiscard]] bool IsMulticore() const;
|
||||||
|
|
||||||
|
/// Type used for the frontend to designate a callback for System to re-launch the application
|
||||||
|
/// using a specified program index.
|
||||||
|
using ExecuteProgramCallback = std::function<void(std::size_t)>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a callback from the frontend for System to re-launch the application using a
|
||||||
|
* specified program index.
|
||||||
|
* @param callback Callback from the frontend to relaunch the application.
|
||||||
|
*/
|
||||||
|
void RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructs the frontend to re-launch the application using the specified program_index.
|
||||||
|
* @param program_index Specifies the index within the application of the program to launch.
|
||||||
|
*/
|
||||||
|
void ExecuteProgram(std::size_t program_index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
System();
|
System();
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ constexpr std::array partition_names{
|
|||||||
"logo",
|
"logo",
|
||||||
};
|
};
|
||||||
|
|
||||||
XCI::XCI(VirtualFile file_)
|
XCI::XCI(VirtualFile file_, std::size_t program_index)
|
||||||
: file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA},
|
: file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA},
|
||||||
partitions(partition_names.size()),
|
partitions(partition_names.size()),
|
||||||
partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} {
|
partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} {
|
||||||
@ -62,7 +62,8 @@ XCI::XCI(VirtualFile file_)
|
|||||||
}
|
}
|
||||||
|
|
||||||
secure_partition = std::make_shared<NSP>(
|
secure_partition = std::make_shared<NSP>(
|
||||||
main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]));
|
main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]),
|
||||||
|
program_index);
|
||||||
|
|
||||||
ncas = secure_partition->GetNCAsCollapsed();
|
ncas = secure_partition->GetNCAsCollapsed();
|
||||||
program =
|
program =
|
||||||
|
@ -78,7 +78,7 @@ enum class XCIPartition : u8 { Update, Normal, Secure, Logo };
|
|||||||
|
|
||||||
class XCI : public ReadOnlyVfsDirectory {
|
class XCI : public ReadOnlyVfsDirectory {
|
||||||
public:
|
public:
|
||||||
explicit XCI(VirtualFile file);
|
explicit XCI(VirtualFile file, std::size_t program_index = 0);
|
||||||
~XCI() override;
|
~XCI() override;
|
||||||
|
|
||||||
Loader::ResultStatus GetStatus() const;
|
Loader::ResultStatus GetStatus() const;
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
|
|
||||||
NSP::NSP(VirtualFile file_)
|
NSP::NSP(VirtualFile file_, std::size_t program_index)
|
||||||
: file(std::move(file_)), status{Loader::ResultStatus::Success},
|
: file(std::move(file_)), program_index(program_index), status{Loader::ResultStatus::Success},
|
||||||
pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} {
|
pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} {
|
||||||
if (pfs->GetStatus() != Loader::ResultStatus::Success) {
|
if (pfs->GetStatus() != Loader::ResultStatus::Success) {
|
||||||
status = pfs->GetStatus();
|
status = pfs->GetStatus();
|
||||||
@ -146,7 +146,7 @@ std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type, TitleType
|
|||||||
if (extracted)
|
if (extracted)
|
||||||
LOG_WARNING(Service_FS, "called on an NSP that is of type extracted.");
|
LOG_WARNING(Service_FS, "called on an NSP that is of type extracted.");
|
||||||
|
|
||||||
const auto title_id_iter = ncas.find(title_id);
|
const auto title_id_iter = ncas.find(title_id + program_index);
|
||||||
if (title_id_iter == ncas.end())
|
if (title_id_iter == ncas.end())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ enum class ContentRecordType : u8;
|
|||||||
|
|
||||||
class NSP : public ReadOnlyVfsDirectory {
|
class NSP : public ReadOnlyVfsDirectory {
|
||||||
public:
|
public:
|
||||||
explicit NSP(VirtualFile file);
|
explicit NSP(VirtualFile file, std::size_t program_index = 0);
|
||||||
~NSP() override;
|
~NSP() override;
|
||||||
|
|
||||||
Loader::ResultStatus GetStatus() const;
|
Loader::ResultStatus GetStatus() const;
|
||||||
@ -69,6 +69,8 @@ private:
|
|||||||
|
|
||||||
VirtualFile file;
|
VirtualFile file;
|
||||||
|
|
||||||
|
const std::size_t program_index;
|
||||||
|
|
||||||
bool extracted = false;
|
bool extracted = false;
|
||||||
Loader::ResultStatus status;
|
Loader::ResultStatus status;
|
||||||
std::map<u64, Loader::ResultStatus> program_status;
|
std::map<u64, Loader::ResultStatus> program_status;
|
||||||
|
@ -1188,9 +1188,9 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
|
|||||||
{102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"},
|
{102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"},
|
||||||
{110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"},
|
{110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"},
|
||||||
{111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"},
|
{111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"},
|
||||||
{120, nullptr, "ExecuteProgram"},
|
{120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"},
|
||||||
{121, nullptr, "ClearUserChannel"},
|
{121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"},
|
||||||
{122, nullptr, "UnpopToUserChannel"},
|
{122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"},
|
||||||
{123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},
|
{123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},
|
||||||
{124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
|
{124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
|
||||||
{130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
|
{130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
|
||||||
@ -1561,6 +1561,34 @@ void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLEReque
|
|||||||
rb.Push<u32>(0);
|
rb.Push<u32>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IApplicationFunctions::ExecuteProgram(Kernel::HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
[[maybe_unused]] const auto unk_1 = rp.Pop<u32>();
|
||||||
|
[[maybe_unused]] const auto unk_2 = rp.Pop<u32>();
|
||||||
|
const auto program_index = rp.Pop<u64>();
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
|
||||||
|
system.ExecuteProgram(program_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IApplicationFunctions::ClearUserChannel(Kernel::HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IApplicationFunctions::UnpopToUserChannel(Kernel::HLERequestContext& ctx) {
|
||||||
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) {
|
void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||||
|
|
||||||
|
@ -287,6 +287,9 @@ private:
|
|||||||
void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx);
|
void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx);
|
||||||
void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx);
|
void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx);
|
||||||
void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx);
|
void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx);
|
||||||
|
void ExecuteProgram(Kernel::HLERequestContext& ctx);
|
||||||
|
void ClearUserChannel(Kernel::HLERequestContext& ctx);
|
||||||
|
void UnpopToUserChannel(Kernel::HLERequestContext& ctx);
|
||||||
void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx);
|
void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx);
|
||||||
void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx);
|
void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx);
|
||||||
void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx);
|
void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx);
|
||||||
|
@ -198,10 +198,11 @@ AppLoader::~AppLoader() = default;
|
|||||||
* @param system The system context to use.
|
* @param system The system context to use.
|
||||||
* @param file The file to retrieve the loader for
|
* @param file The file to retrieve the loader for
|
||||||
* @param type The file type
|
* @param type The file type
|
||||||
|
* @param program_index Specifies the index within the container of the program to launch.
|
||||||
* @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type
|
* @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type
|
||||||
*/
|
*/
|
||||||
static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file,
|
static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file,
|
||||||
FileType type) {
|
FileType type, std::size_t program_index) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
// Standard ELF file format.
|
// Standard ELF file format.
|
||||||
case FileType::ELF:
|
case FileType::ELF:
|
||||||
@ -222,7 +223,7 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V
|
|||||||
// NX XCI (nX Card Image) file format.
|
// NX XCI (nX Card Image) file format.
|
||||||
case FileType::XCI:
|
case FileType::XCI:
|
||||||
return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(),
|
return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(),
|
||||||
system.GetContentProvider());
|
system.GetContentProvider(), program_index);
|
||||||
|
|
||||||
// NX NAX (NintendoAesXts) file format.
|
// NX NAX (NintendoAesXts) file format.
|
||||||
case FileType::NAX:
|
case FileType::NAX:
|
||||||
@ -231,7 +232,7 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V
|
|||||||
// NX NSP (Nintendo Submission Package) file format
|
// NX NSP (Nintendo Submission Package) file format
|
||||||
case FileType::NSP:
|
case FileType::NSP:
|
||||||
return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(),
|
return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(),
|
||||||
system.GetContentProvider());
|
system.GetContentProvider(), program_index);
|
||||||
|
|
||||||
// NX KIP (Kernel Internal Process) file format
|
// NX KIP (Kernel Internal Process) file format
|
||||||
case FileType::KIP:
|
case FileType::KIP:
|
||||||
@ -246,7 +247,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file) {
|
std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file,
|
||||||
|
std::size_t program_index) {
|
||||||
FileType type = IdentifyFile(file);
|
FileType type = IdentifyFile(file);
|
||||||
const FileType filename_type = GuessFromFilename(file->GetName());
|
const FileType filename_type = GuessFromFilename(file->GetName());
|
||||||
|
|
||||||
@ -260,7 +262,7 @@ std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile
|
|||||||
|
|
||||||
LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type));
|
LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type));
|
||||||
|
|
||||||
return GetFileLoader(system, std::move(file), type);
|
return GetFileLoader(system, std::move(file), type, program_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Loader
|
} // namespace Loader
|
||||||
|
@ -293,9 +293,11 @@ protected:
|
|||||||
*
|
*
|
||||||
* @param system The system context.
|
* @param system The system context.
|
||||||
* @param file The bootable file.
|
* @param file The bootable file.
|
||||||
|
* @param program_index Specifies the index within the container of the program to launch.
|
||||||
*
|
*
|
||||||
* @return the best loader for this file.
|
* @return the best loader for this file.
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file);
|
std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file,
|
||||||
|
std::size_t program_index = 0);
|
||||||
|
|
||||||
} // namespace Loader
|
} // namespace Loader
|
||||||
|
@ -23,8 +23,9 @@ namespace Loader {
|
|||||||
|
|
||||||
AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file,
|
AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file,
|
||||||
const Service::FileSystem::FileSystemController& fsc,
|
const Service::FileSystem::FileSystemController& fsc,
|
||||||
const FileSys::ContentProvider& content_provider)
|
const FileSys::ContentProvider& content_provider,
|
||||||
: AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file)),
|
std::size_t program_index)
|
||||||
|
: AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file, program_index)),
|
||||||
title_id(nsp->GetProgramTitleID()) {
|
title_id(nsp->GetProgramTitleID()) {
|
||||||
|
|
||||||
if (nsp->GetStatus() != ResultStatus::Success) {
|
if (nsp->GetStatus() != ResultStatus::Success) {
|
||||||
|
@ -28,7 +28,8 @@ class AppLoader_NSP final : public AppLoader {
|
|||||||
public:
|
public:
|
||||||
explicit AppLoader_NSP(FileSys::VirtualFile file,
|
explicit AppLoader_NSP(FileSys::VirtualFile file,
|
||||||
const Service::FileSystem::FileSystemController& fsc,
|
const Service::FileSystem::FileSystemController& fsc,
|
||||||
const FileSys::ContentProvider& content_provider);
|
const FileSys::ContentProvider& content_provider,
|
||||||
|
std::size_t program_index);
|
||||||
~AppLoader_NSP() override;
|
~AppLoader_NSP() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,8 +22,9 @@ namespace Loader {
|
|||||||
|
|
||||||
AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file,
|
AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file,
|
||||||
const Service::FileSystem::FileSystemController& fsc,
|
const Service::FileSystem::FileSystemController& fsc,
|
||||||
const FileSys::ContentProvider& content_provider)
|
const FileSys::ContentProvider& content_provider,
|
||||||
: AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)),
|
std::size_t program_index)
|
||||||
|
: AppLoader(file), xci(std::make_unique<FileSys::XCI>(file, program_index)),
|
||||||
nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) {
|
nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) {
|
||||||
if (xci->GetStatus() != ResultStatus::Success) {
|
if (xci->GetStatus() != ResultStatus::Success) {
|
||||||
return;
|
return;
|
||||||
|
@ -28,7 +28,8 @@ class AppLoader_XCI final : public AppLoader {
|
|||||||
public:
|
public:
|
||||||
explicit AppLoader_XCI(FileSys::VirtualFile file,
|
explicit AppLoader_XCI(FileSys::VirtualFile file,
|
||||||
const Service::FileSystem::FileSystemController& fsc,
|
const Service::FileSystem::FileSystemController& fsc,
|
||||||
const FileSys::ContentProvider& content_provider);
|
const FileSys::ContentProvider& content_provider,
|
||||||
|
std::size_t program_index);
|
||||||
~AppLoader_XCI() override;
|
~AppLoader_XCI() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -302,6 +302,12 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
|
|||||||
this->setMouseTracking(true);
|
this->setMouseTracking(true);
|
||||||
|
|
||||||
connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete);
|
connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete);
|
||||||
|
connect(this, &GRenderWindow::ExecuteProgramSignal, parent, &GMainWindow::OnExecuteProgram,
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GRenderWindow::ExecuteProgram(std::size_t program_index) {
|
||||||
|
emit ExecuteProgramSignal(program_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
GRenderWindow::~GRenderWindow() {
|
GRenderWindow::~GRenderWindow() {
|
||||||
|
@ -166,6 +166,12 @@ public:
|
|||||||
|
|
||||||
std::pair<u32, u32> ScaleTouch(const QPointF& pos) const;
|
std::pair<u32, u32> ScaleTouch(const QPointF& pos) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructs the window to re-launch the application using the specified program_index.
|
||||||
|
* @param program_index Specifies the index within the application of the program to launch.
|
||||||
|
*/
|
||||||
|
void ExecuteProgram(std::size_t program_index);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void OnEmulationStarting(EmuThread* emu_thread);
|
void OnEmulationStarting(EmuThread* emu_thread);
|
||||||
void OnEmulationStopping();
|
void OnEmulationStopping();
|
||||||
@ -175,6 +181,7 @@ signals:
|
|||||||
/// Emitted when the window is closed
|
/// Emitted when the window is closed
|
||||||
void Closed();
|
void Closed();
|
||||||
void FirstFrameDisplayed();
|
void FirstFrameDisplayed();
|
||||||
|
void ExecuteProgramSignal(std::size_t program_index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void TouchBeginEvent(const QTouchEvent* event);
|
void TouchBeginEvent(const QTouchEvent* event);
|
||||||
|
@ -978,7 +978,7 @@ void GMainWindow::AllowOSSleep() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GMainWindow::LoadROM(const QString& filename) {
|
bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) {
|
||||||
// Shutdown previous session if the emu thread is still active...
|
// Shutdown previous session if the emu thread is still active...
|
||||||
if (emu_thread != nullptr)
|
if (emu_thread != nullptr)
|
||||||
ShutdownGame();
|
ShutdownGame();
|
||||||
@ -1003,7 +1003,8 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
|||||||
|
|
||||||
system.RegisterHostThread();
|
system.RegisterHostThread();
|
||||||
|
|
||||||
const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())};
|
const Core::System::ResultStatus result{
|
||||||
|
system.Load(*render_window, filename.toStdString(), program_index)};
|
||||||
|
|
||||||
const auto drd_callout =
|
const auto drd_callout =
|
||||||
(UISettings::values.callout_flags & static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0;
|
(UISettings::values.callout_flags & static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0;
|
||||||
@ -1085,14 +1086,18 @@ void GMainWindow::SelectAndSetCurrentUser() {
|
|||||||
Settings::values.current_user = dialog.GetIndex();
|
Settings::values.current_user = dialog.GetIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::BootGame(const QString& filename) {
|
void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
|
||||||
LOG_INFO(Frontend, "yuzu starting...");
|
LOG_INFO(Frontend, "yuzu starting...");
|
||||||
StoreRecentFile(filename); // Put the filename on top of the list
|
StoreRecentFile(filename); // Put the filename on top of the list
|
||||||
|
|
||||||
u64 title_id{0};
|
u64 title_id{0};
|
||||||
|
|
||||||
|
last_filename_booted = filename;
|
||||||
|
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = Core::System::GetInstance();
|
||||||
const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData());
|
const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData());
|
||||||
const auto loader = Loader::GetLoader(system, v_file);
|
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)) {
|
||||||
// Load per game settings
|
// Load per game settings
|
||||||
Config per_game_config(fmt::format("{:016X}", title_id), Config::ConfigType::PerGameConfig);
|
Config per_game_config(fmt::format("{:016X}", title_id), Config::ConfigType::PerGameConfig);
|
||||||
@ -1106,7 +1111,7 @@ void GMainWindow::BootGame(const QString& filename) {
|
|||||||
SelectAndSetCurrentUser();
|
SelectAndSetCurrentUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!LoadROM(filename))
|
if (!LoadROM(filename, program_index))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Create and start the emulation thread
|
// Create and start the emulation thread
|
||||||
@ -1114,6 +1119,10 @@ void GMainWindow::BootGame(const QString& filename) {
|
|||||||
emit EmulationStarting(emu_thread.get());
|
emit EmulationStarting(emu_thread.get());
|
||||||
emu_thread->start();
|
emu_thread->start();
|
||||||
|
|
||||||
|
// Register an ExecuteProgram callback such that Core can execute a sub-program
|
||||||
|
system.RegisterExecuteProgramCallback(
|
||||||
|
[this](std::size_t program_index) { render_window->ExecuteProgram(program_index); });
|
||||||
|
|
||||||
connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame);
|
connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame);
|
||||||
// BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views
|
// BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views
|
||||||
// before the CPU continues
|
// before the CPU continues
|
||||||
@ -2136,6 +2145,11 @@ void GMainWindow::OnLoadComplete() {
|
|||||||
loading_screen->OnLoadComplete();
|
loading_screen->OnLoadComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GMainWindow::OnExecuteProgram(std::size_t program_index) {
|
||||||
|
ShutdownGame();
|
||||||
|
BootGame(last_filename_booted, program_index);
|
||||||
|
}
|
||||||
|
|
||||||
void GMainWindow::ErrorDisplayDisplayError(QString body) {
|
void GMainWindow::ErrorDisplayDisplayError(QString body) {
|
||||||
QMessageBox::critical(this, tr("Error Display"), body);
|
QMessageBox::critical(this, tr("Error Display"), body);
|
||||||
emit ErrorDisplayFinished();
|
emit ErrorDisplayFinished();
|
||||||
|
@ -131,6 +131,7 @@ signals:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void OnLoadComplete();
|
void OnLoadComplete();
|
||||||
|
void OnExecuteProgram(std::size_t program_index);
|
||||||
void ControllerSelectorReconfigureControllers(
|
void ControllerSelectorReconfigureControllers(
|
||||||
const Core::Frontend::ControllerParameters& parameters);
|
const Core::Frontend::ControllerParameters& parameters);
|
||||||
void ErrorDisplayDisplayError(QString body);
|
void ErrorDisplayDisplayError(QString body);
|
||||||
@ -154,8 +155,8 @@ private:
|
|||||||
void PreventOSSleep();
|
void PreventOSSleep();
|
||||||
void AllowOSSleep();
|
void AllowOSSleep();
|
||||||
|
|
||||||
bool LoadROM(const QString& filename);
|
bool LoadROM(const QString& filename, std::size_t program_index);
|
||||||
void BootGame(const QString& filename);
|
void BootGame(const QString& filename, std::size_t program_index = 0);
|
||||||
void ShutdownGame();
|
void ShutdownGame();
|
||||||
|
|
||||||
void ShowTelemetryCallout();
|
void ShowTelemetryCallout();
|
||||||
@ -317,6 +318,9 @@ private:
|
|||||||
// Install progress dialog
|
// Install progress dialog
|
||||||
QProgressDialog* install_progress;
|
QProgressDialog* install_progress;
|
||||||
|
|
||||||
|
// Last game booted, used for multi-process apps
|
||||||
|
QString last_filename_booted;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void dropEvent(QDropEvent* event) override;
|
void dropEvent(QDropEvent* event) override;
|
||||||
void dragEnterEvent(QDragEnterEvent* event) override;
|
void dragEnterEvent(QDragEnterEvent* event) override;
|
||||||
|
Loading…
Reference in New Issue
Block a user