aboutsummaryrefslogtreecommitdiff
path: root/src/core/loader
diff options
context:
space:
mode:
authorMaufeat <sahyno1996@gmail.com>2026-08-29 01:04:02 +0200
committercrueter <crueter@eden-emu.dev>2026-08-29 01:04:02 +0200
commit54cd5fb8ebf11b71c676b72a32811873caef20de (patch)
tree20fef6adb49da98d3d87ae152853229bf762a3bb /src/core/loader
parent119291dc77fbe8e4a23eaafa8420c1c8577d1b59 (diff)
[core, hle, video_core, memory] Improve multi-process, display layers, dynamic shader cache and rework overlay (#4238)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions). - [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md) - [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability. ------------------- - Dynamic shader cache reloading capability for qlaunch - Multi-process improvements (thanks to @frank1734), instead of just using the main application we now respect caller process (also did it for HID devices while I was at it) - Layer stack masks & shared buffer screenshot for video core, added different masks (screenshot, recording, etc.) this was discovered as an issue due to how in qlaunch the transition was not right between applications. May not be perfect but also fixes screenshots while using qlaunch - Reworked overlay display management (input and visibility) - instead of random numbers as I've previously did, I decided to add an AppletZIndex enum for better readability. Also split capability of input by touch and gamepad. - etc. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4238 Reviewed-by: Samuel <lizzie@eden-emu.dev> Reviewed-by: CamilleLaVey <camillelavey99@gmail.com> Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Diffstat (limited to 'src/core/loader')
-rw-r--r--src/core/loader/loader.cpp39
-rw-r--r--src/core/loader/nca.cpp46
-rw-r--r--src/core/loader/nca.h12
-rw-r--r--src/core/loader/nso.cpp5
-rw-r--r--src/core/loader/nsp.cpp5
5 files changed, 98 insertions, 9 deletions
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 69bfa2e879..90e23ccc11 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -17,6 +17,8 @@
#include "core/core.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/common_funcs.h"
+#include "core/file_sys/content_archive.h"
+#include "core/file_sys/registered_cache.h"
#include "core/file_sys/submission_package.h"
#include "core/hle/kernel/k_process.h"
#include "core/loader/deconstructed_rom_directory.h"
@@ -41,6 +43,38 @@ std::optional<FileType> IdentifyFileLoader(FileSys::VirtualFile file) {
return std::nullopt;
}
+struct IndexedProgram {
+ FileSys::VirtualFile file;
+ u64 program_id;
+ bool update_only;
+};
+
+std::optional<IndexedProgram> ResolveIndexedProgram(Core::System& system, u64 program_id,
+ std::size_t program_index) {
+ if (program_index == 0 || program_id == 0) {
+ return std::nullopt;
+ }
+
+ const auto target_id = FileSys::GetBaseTitleIDWithProgramIndex(program_id, program_index);
+ const auto& provider = system.GetContentProvider();
+
+ if (auto base = provider.GetEntryRaw(target_id, FileSys::ContentRecordType::Program)) {
+ LOG_INFO(Loader, "Program index {} resolved to {:016X}", program_index, target_id);
+ return IndexedProgram{std::move(base), target_id, false};
+ }
+
+ const auto update_id = FileSys::GetUpdateTitleID(target_id);
+ if (auto update = provider.GetEntryRaw(update_id, FileSys::ContentRecordType::Program)) {
+ LOG_INFO(Loader, "Program index {} has no base program, loading it from update {:016X}",
+ program_index, update_id);
+ return IndexedProgram{std::move(update), target_id, true};
+ }
+
+ LOG_WARNING(Loader, "No program NCA for {:016X} (index {}), falling back to the container",
+ target_id, program_index);
+ return std::nullopt;
+}
+
std::shared_ptr<FileSys::NSP> OpenContainerAsNsp(FileSys::VirtualFile file, FileType type,
u64 program_id = 0,
std::size_t program_index = 0) {
@@ -321,6 +355,11 @@ std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile
return nullptr;
}
+ if (const auto indexed = ResolveIndexedProgram(system, program_id, program_index)) {
+ return std::make_unique<AppLoader_NCA>(
+ indexed->file, indexed->update_only ? indexed->program_id : 0);
+ }
+
FileType type = IdentifyFile(file);
const FileType filename_type = GuessFromFilename(file->GetName());
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index b656b9fe96..2f9cd68e9c 100644
--- a/src/core/loader/nca.cpp
+++ b/src/core/loader/nca.cpp
@@ -12,7 +12,9 @@
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/file_sys/content_archive.h"
+#include "core/file_sys/control_metadata.h"
#include "core/file_sys/nca_metadata.h"
+#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs_factory.h"
#include "core/hle/kernel/k_process.h"
@@ -33,8 +35,14 @@ static u32 CalculatePointerBufferSize(size_t heap_size) {
}
}
-AppLoader_NCA::AppLoader_NCA(FileSys::VirtualFile file_)
- : AppLoader(std::move(file_)), nca(std::make_unique<FileSys::NCA>(file)) {}
+AppLoader_NCA::AppLoader_NCA(FileSys::VirtualFile file_, u64 update_only_program_id_)
+ : AppLoader(std::move(file_)),
+ nca(std::make_unique<FileSys::NCA>(file, nullptr, update_only_program_id_ != 0)),
+ update_only_program_id(update_only_program_id_) {}
+
+u64 AppLoader_NCA::GetProgramId() const {
+ return update_only_program_id != 0 ? update_only_program_id : nca->GetTitleId();
+}
AppLoader_NCA::~AppLoader_NCA() = default;
@@ -110,11 +118,21 @@ AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::KProcess& process, Core::S
}
LOG_INFO(Loader, "Set pointer buffer size to {:#x} bytes for ProgramID {:#018x} (Heap size: {:#x})",
- process.GetPointerBufferSize(), nca->GetTitleId(), heap_size);
+ process.GetPointerBufferSize(), GetProgramId(), heap_size);
+
+ auto metadata =
+ FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, this->GetProgramId());
+ if (metadata.first != nullptr) {
+ nacp = std::move(metadata.first);
+ LOG_INFO(Loader, "Control data for {:016X}: name=\"{}\" supported_languages={:08X}",
+ this->GetProgramId(), nacp->GetApplicationName(), nacp->GetSupportedLanguages());
+ } else {
+ LOG_WARNING(Loader, "No control data found for program {:016X}", this->GetProgramId());
+ }
// Register the process in the file system controller
system.GetFileSystemController().RegisterProcess(
- process.GetProcessId(), nca->GetTitleId(),
+ process.GetProcessId(), GetProgramId(),
std::make_shared<FileSys::RomFSFactory>(*this, system.GetContentProvider(),
system.GetFileSystemController()));
@@ -222,7 +240,25 @@ ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
return ResultStatus::ErrorNotInitialized;
}
- out_program_id = nca->GetTitleId();
+ out_program_id = GetProgramId();
+ return ResultStatus::Success;
+}
+
+ResultStatus AppLoader_NCA::ReadControlData(FileSys::NACP& out_control) {
+ if (nacp == nullptr) {
+ return ResultStatus::ErrorNoControl;
+ }
+
+ out_control = *nacp;
+ return ResultStatus::Success;
+}
+
+ResultStatus AppLoader_NCA::ReadTitle(std::string& out_title) {
+ if (nacp == nullptr) {
+ return ResultStatus::ErrorNoControl;
+ }
+
+ out_title = nacp->GetApplicationName();
return ResultStatus::Success;
}
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h
index 96779e27fc..cf63822120 100644
--- a/src/core/loader/nca.h
+++ b/src/core/loader/nca.h
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -11,6 +14,7 @@ class System;
}
namespace FileSys {
+class NACP;
class NCA;
}
@@ -21,7 +25,7 @@ class AppLoader_DeconstructedRomDirectory;
/// Loads an NCA file
class AppLoader_NCA final : public AppLoader {
public:
- explicit AppLoader_NCA(FileSys::VirtualFile file_);
+ explicit AppLoader_NCA(FileSys::VirtualFile file_, u64 update_only_program_id = 0);
~AppLoader_NCA() override;
/**
@@ -43,14 +47,20 @@ public:
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
+ ResultStatus ReadControlData(FileSys::NACP& out_control) override;
+ ResultStatus ReadTitle(std::string& out_title) override;
ResultStatus ReadBanner(std::vector<u8>& buffer) override;
ResultStatus ReadLogo(std::vector<u8>& buffer) override;
ResultStatus ReadNSOModules(Modules& modules) override;
+ u64 GetProgramId() const;
+
private:
std::unique_ptr<FileSys::NCA> nca;
+ u64 update_only_program_id{};
+ std::unique_ptr<FileSys::NACP> nacp;
std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader;
};
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index d8b4e018f7..0a3dc5885b 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -209,7 +209,10 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
// Apply cheats if they exist and the program has a valid title ID
if (pm) {
- system.SetApplicationProcessBuildID(nso_header.build_id);
+ // TODO(Maufeat): Check if there is a better way to check
+ if (name == "main")
+ system.SetApplicationProcessBuildID(nso_header.build_id);
+
const auto cheats = pm->CreateCheatList(nso_header.build_id);
if (!cheats.empty()) {
system.RegisterCheatList(cheats, nso_header.build_id, load_base, image_size);
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index 726bb428f6..cfc908b4ef 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -8,6 +8,7 @@
#include "common/common_types.h"
#include "core/core.h"
+#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/nca_metadata.h"
@@ -37,13 +38,13 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_,
secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS(), false);
} else {
const auto control_nca =
- nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control);
+ nsp->GetNCA(FileSys::GetBaseTitleID(nsp->GetProgramTitleID()), FileSys::ContentRecordType::Control);
if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) {
return;
}
std::tie(nacp_file, icon_file) = [this, &content_provider, &control_nca, &fsc] {
- const FileSys::PatchManager pm{nsp->GetProgramTitleID(), fsc, content_provider};
+ const FileSys::PatchManager pm{FileSys::GetBaseTitleID(nsp->GetProgramTitleID()), fsc, content_provider};
return pm.ParseControlNCA(*control_nca);
}();