early-access version 1869

main
pineappleEA 2021-07-11 22:43:19 +02:00
parent 2c7191ed4b
commit c28ecd0f43
30 changed files with 272 additions and 171 deletions

View File

@ -47,9 +47,10 @@ if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE)
endif() endif()
if(EXISTS ${PROJECT_SOURCE_DIR}/hooks/pre-commit AND NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit) if(EXISTS ${PROJECT_SOURCE_DIR}/hooks/pre-commit AND NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit)
message(STATUS "Copying pre-commit hook") if (EXISTS ${PROJECT_SOURCE_DIR}/.git/)
file(COPY hooks/pre-commit message(STATUS "Copying pre-commit hook")
DESTINATION ${PROJECT_SOURCE_DIR}/.git/hooks) file(COPY hooks/pre-commit DESTINATION ${PROJECT_SOURCE_DIR}/.git/hooks)
endif()
endif() endif()
# Sanity check : Check that all submodules are present # Sanity check : Check that all submodules are present

View File

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 1868. This is the source code for early-access 1869.
## Legal Notice ## Legal Notice

View File

@ -339,7 +339,7 @@ struct Values {
Setting<bool> use_nvdec_emulation{true, "use_nvdec_emulation"}; Setting<bool> use_nvdec_emulation{true, "use_nvdec_emulation"};
Setting<bool> accelerate_astc{true, "accelerate_astc"}; Setting<bool> accelerate_astc{true, "accelerate_astc"};
Setting<bool> use_vsync{true, "use_vsync"}; Setting<bool> use_vsync{true, "use_vsync"};
Setting<bool> disable_fps_limit{false, "disable_fps_limit"}; BasicSetting<bool> disable_fps_limit{false, "disable_fps_limit"};
Setting<ShaderBackend> shader_backend{ShaderBackend::GLASM, "shader_backend"}; Setting<ShaderBackend> shader_backend{ShaderBackend::GLASM, "shader_backend"};
Setting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"}; Setting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
Setting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"}; Setting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};

View File

@ -216,9 +216,9 @@ struct System::Impl {
} }
ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath, ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath,
std::size_t program_index) { u64 program_id, 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); program_id, 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);
@ -269,11 +269,10 @@ struct System::Impl {
} }
} }
u64 title_id{0}; if (app_loader->ReadProgramId(program_id) != Loader::ResultStatus::Success) {
if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", load_result); LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", load_result);
} }
perf_stats = std::make_unique<PerfStats>(title_id); perf_stats = std::make_unique<PerfStats>(program_id);
// Reset counters and set time origin to current frame // Reset counters and set time origin to current frame
GetAndResetPerfStats(); GetAndResetPerfStats();
perf_stats->BeginSystemFrame(); perf_stats->BeginSystemFrame();
@ -459,8 +458,8 @@ void System::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,
std::size_t program_index) { u64 program_id, std::size_t program_index) {
return impl->Load(*this, emu_window, filepath, program_index); return impl->Load(*this, emu_window, filepath, program_id, program_index);
} }
bool System::IsPoweredOn() const { bool System::IsPoweredOn() const {

View File

@ -175,7 +175,7 @@ public:
* @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); u64 program_id = 0, 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

View File

@ -29,7 +29,7 @@ constexpr std::array partition_names{
"logo", "logo",
}; };
XCI::XCI(VirtualFile file_, std::size_t program_index) XCI::XCI(VirtualFile file_, u64 program_id, 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()} {
@ -63,12 +63,12 @@ XCI::XCI(VirtualFile file_, std::size_t program_index)
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); program_id, program_index);
ncas = secure_partition->GetNCAsCollapsed(); ncas = secure_partition->GetNCAsCollapsed();
program = program =
secure_partition->GetNCA(secure_partition->GetProgramTitleID(), ContentRecordType::Program); secure_partition->GetNCA(secure_partition->GetProgramTitleID(), ContentRecordType::Program);
program_nca_status = secure_partition->GetProgramStatus(secure_partition->GetProgramTitleID()); program_nca_status = secure_partition->GetProgramStatus();
if (program_nca_status == Loader::ResultStatus::ErrorNSPMissingProgramNCA) { if (program_nca_status == Loader::ResultStatus::ErrorNSPMissingProgramNCA) {
program_nca_status = Loader::ResultStatus::ErrorXCIMissingProgramNCA; program_nca_status = Loader::ResultStatus::ErrorXCIMissingProgramNCA;
} }
@ -174,6 +174,10 @@ u64 XCI::GetProgramTitleID() const {
return secure_partition->GetProgramTitleID(); return secure_partition->GetProgramTitleID();
} }
std::vector<u64> XCI::GetProgramTitleIDs() const {
return secure_partition->GetProgramTitleIDs();
}
u32 XCI::GetSystemUpdateVersion() { u32 XCI::GetSystemUpdateVersion() {
const auto update = GetPartition(XCIPartition::Update); const auto update = GetPartition(XCIPartition::Update);
if (update == nullptr) { if (update == nullptr) {
@ -229,9 +233,11 @@ const std::vector<std::shared_ptr<NCA>>& XCI::GetNCAs() const {
} }
std::shared_ptr<NCA> XCI::GetNCAByType(NCAContentType type) const { std::shared_ptr<NCA> XCI::GetNCAByType(NCAContentType type) const {
const auto iter = const auto program_id = secure_partition->GetProgramTitleID();
std::find_if(ncas.begin(), ncas.end(), const auto iter = std::find_if(
[type](const std::shared_ptr<NCA>& nca) { return nca->GetType() == type; }); ncas.begin(), ncas.end(), [this, type, program_id](const std::shared_ptr<NCA>& nca) {
return nca->GetType() == type && nca->GetTitleId() == program_id;
});
return iter == ncas.end() ? nullptr : *iter; return iter == ncas.end() ? nullptr : *iter;
} }

View File

@ -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, std::size_t program_index = 0); explicit XCI(VirtualFile file, u64 program_id = 0, size_t program_index = 0);
~XCI() override; ~XCI() override;
Loader::ResultStatus GetStatus() const; Loader::ResultStatus GetStatus() const;
@ -104,6 +104,7 @@ public:
VirtualFile GetLogoPartitionRaw() const; VirtualFile GetLogoPartitionRaw() const;
u64 GetProgramTitleID() const; u64 GetProgramTitleID() const;
std::vector<u64> GetProgramTitleIDs() const;
u32 GetSystemUpdateVersion(); u32 GetSystemUpdateVersion();
u64 GetSystemUpdateTitleID() const; u64 GetSystemUpdateTitleID() const;

View File

@ -20,8 +20,9 @@
namespace FileSys { namespace FileSys {
NSP::NSP(VirtualFile file_, std::size_t program_index_) NSP::NSP(VirtualFile file_, u64 title_id_, std::size_t program_index_)
: file(std::move(file_)), program_index(program_index_), status{Loader::ResultStatus::Success}, : file(std::move(file_)), expected_program_id(title_id_),
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();
@ -46,60 +47,59 @@ Loader::ResultStatus NSP::GetStatus() const {
return status; return status;
} }
Loader::ResultStatus NSP::GetProgramStatus(u64 title_id) const { Loader::ResultStatus NSP::GetProgramStatus() const {
if (IsExtractedType() && GetExeFS() != nullptr && FileSys::IsDirectoryExeFS(GetExeFS())) { if (IsExtractedType() && GetExeFS() != nullptr && FileSys::IsDirectoryExeFS(GetExeFS())) {
return Loader::ResultStatus::Success; return Loader::ResultStatus::Success;
} }
const auto iter = program_status.find(title_id); const auto iter = program_status.find(GetProgramTitleID());
if (iter == program_status.end()) if (iter == program_status.end())
return Loader::ResultStatus::ErrorNSPMissingProgramNCA; return Loader::ResultStatus::ErrorNSPMissingProgramNCA;
return iter->second; return iter->second;
} }
u64 NSP::GetFirstTitleID() const {
if (IsExtractedType()) {
return GetProgramTitleID();
}
if (program_status.empty())
return 0;
return program_status.begin()->first;
}
u64 NSP::GetProgramTitleID() const { u64 NSP::GetProgramTitleID() const {
if (IsExtractedType()) { if (IsExtractedType()) {
if (GetExeFS() == nullptr || !IsDirectoryExeFS(GetExeFS())) { return GetExtractedTitleID();
return 0; }
}
ProgramMetadata meta; auto program_id = expected_program_id;
if (meta.Load(GetExeFS()->GetFile("main.npdm")) == Loader::ResultStatus::Success) { if (program_id == 0) {
return meta.GetTitleID(); if (!program_status.empty()) {
} else { program_id = program_status.begin()->first;
return 0;
} }
} }
const auto out = GetFirstTitleID(); program_id = program_id + program_index;
if ((out & 0x800) == 0) if (program_status.find(program_id) != program_status.end()) {
return out; return program_id;
}
const auto ids = GetTitleIDs(); const auto ids = GetProgramTitleIDs();
const auto iter = const auto iter =
std::find_if(ids.begin(), ids.end(), [](u64 tid) { return (tid & 0x800) == 0; }); std::find_if(ids.begin(), ids.end(), [](u64 tid) { return (tid & 0x800) == 0; });
return iter == ids.end() ? out : *iter; return iter == ids.end() ? 0 : *iter;
} }
std::vector<u64> NSP::GetTitleIDs() const { u64 NSP::GetExtractedTitleID() const {
if (IsExtractedType()) { if (GetExeFS() == nullptr || !IsDirectoryExeFS(GetExeFS())) {
return {GetProgramTitleID()}; return 0;
} }
std::vector<u64> out; ProgramMetadata meta;
out.reserve(ncas.size()); if (meta.Load(GetExeFS()->GetFile("main.npdm")) == Loader::ResultStatus::Success) {
for (const auto& kv : ncas) return meta.GetTitleID();
out.push_back(kv.first); } else {
return 0;
}
}
std::vector<u64> NSP::GetProgramTitleIDs() const {
if (IsExtractedType()) {
return {GetExtractedTitleID()};
}
std::vector<u64> out{program_ids.cbegin(), program_ids.cend()};
return out; return out;
} }
@ -142,11 +142,12 @@ NSP::GetNCAs() const {
return ncas; return ncas;
} }
std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type, TitleType title_type) const { std::shared_ptr<NCA> NSP::GetNCA(u64 title_id_, ContentRecordType type,
TitleType title_type) const {
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 + program_index); const auto title_id_iter = ncas.find(title_id_);
if (title_id_iter == ncas.end()) if (title_id_iter == ncas.end())
return nullptr; return nullptr;
@ -157,10 +158,10 @@ std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type, TitleType
return type_iter->second; return type_iter->second;
} }
VirtualFile NSP::GetNCAFile(u64 title_id, ContentRecordType type, TitleType title_type) const { VirtualFile NSP::GetNCAFile(u64 title_id_, ContentRecordType type, TitleType title_type) const {
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 nca = GetNCA(title_id, type); const auto nca = GetNCA(title_id_, type, title_type);
if (nca != nullptr) if (nca != nullptr)
return nca->GetBaseFile(); return nca->GetBaseFile();
return nullptr; return nullptr;
@ -286,6 +287,7 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
if (next_nca->GetType() == NCAContentType::Program) { if (next_nca->GetType() == NCAContentType::Program) {
program_status[next_nca->GetTitleId()] = next_nca->GetStatus(); program_status[next_nca->GetTitleId()] = next_nca->GetStatus();
program_ids.insert(next_nca->GetTitleId() & 0xFFFFFFFFFFFFF000);
} }
if (next_nca->GetStatus() != Loader::ResultStatus::Success && if (next_nca->GetStatus() != Loader::ResultStatus::Success &&

View File

@ -6,6 +6,7 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <set>
#include <vector> #include <vector>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/file_sys/vfs.h" #include "core/file_sys/vfs.h"
@ -27,15 +28,15 @@ enum class ContentRecordType : u8;
class NSP : public ReadOnlyVfsDirectory { class NSP : public ReadOnlyVfsDirectory {
public: public:
explicit NSP(VirtualFile file_, std::size_t program_index_ = 0); explicit NSP(VirtualFile file_, u64 title_id = 0, std::size_t program_index_ = 0);
~NSP() override; ~NSP() override;
Loader::ResultStatus GetStatus() const; Loader::ResultStatus GetStatus() const;
Loader::ResultStatus GetProgramStatus(u64 title_id) const; Loader::ResultStatus GetProgramStatus() const;
// Should only be used when one title id can be assured. // Should only be used when one title id can be assured.
u64 GetFirstTitleID() const;
u64 GetProgramTitleID() const; u64 GetProgramTitleID() const;
std::vector<u64> GetTitleIDs() const; u64 GetExtractedTitleID() const;
std::vector<u64> GetProgramTitleIDs() const;
bool IsExtractedType() const; bool IsExtractedType() const;
@ -69,6 +70,7 @@ private:
VirtualFile file; VirtualFile file;
const u64 expected_program_id;
const std::size_t program_index; const std::size_t program_index;
bool extracted = false; bool extracted = false;
@ -78,6 +80,7 @@ private:
std::shared_ptr<PartitionFilesystem> pfs; std::shared_ptr<PartitionFilesystem> pfs;
// Map title id -> {map type -> NCA} // Map title id -> {map type -> NCA}
std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> ncas; std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> ncas;
std::set<u64> program_ids;
std::vector<VirtualFile> ticket_files; std::vector<VirtualFile> ticket_files;
Core::Crypto::KeyManager& keys; Core::Crypto::KeyManager& keys;

View File

@ -206,7 +206,8 @@ AppLoader::~AppLoader() = default;
* @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, std::size_t program_index) { FileType type, u64 program_id,
std::size_t program_index) {
switch (type) { switch (type) {
// Standard ELF file format. // Standard ELF file format.
case FileType::ELF: case FileType::ELF:
@ -227,7 +228,8 @@ 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(), program_index); system.GetContentProvider(), program_id,
program_index);
// NX NAX (NintendoAesXts) file format. // NX NAX (NintendoAesXts) file format.
case FileType::NAX: case FileType::NAX:
@ -236,7 +238,8 @@ 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(), program_index); system.GetContentProvider(), program_id,
program_index);
// NX KIP (Kernel Internal Process) file format // NX KIP (Kernel Internal Process) file format
case FileType::KIP: case FileType::KIP:
@ -252,7 +255,7 @@ 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) { u64 program_id, 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());
@ -266,7 +269,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, program_index); return GetFileLoader(system, std::move(file), type, program_id, program_index);
} }
} // namespace Loader } // namespace Loader

View File

@ -226,6 +226,17 @@ public:
return ResultStatus::ErrorNotImplemented; return ResultStatus::ErrorNotImplemented;
} }
/**
* Get the program ids of the application
*
* @param[out] out_program_ids Reference to store program ids into
*
* @return ResultStatus result of function
*/
virtual ResultStatus ReadProgramIds(std::vector<u64>& out_program_ids) {
return ResultStatus::ErrorNotImplemented;
}
/** /**
* Get the RomFS of the application * Get the RomFS of the application
* Since the RomFS can be huge, we return a file reference instead of copying to a buffer * Since the RomFS can be huge, we return a file reference instead of copying to a buffer
@ -324,6 +335,6 @@ protected:
* @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); u64 program_id = 0, std::size_t program_index = 0);
} // namespace Loader } // namespace Loader

View File

@ -23,10 +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, u64 program_id,
std::size_t program_index) std::size_t program_index)
: AppLoader(file_), nsp(std::make_unique<FileSys::NSP>(file_, program_index)), : AppLoader(file_), nsp(std::make_unique<FileSys::NSP>(file_, program_id, program_index)) {
title_id(nsp->GetProgramTitleID()) {
if (nsp->GetStatus() != ResultStatus::Success) { if (nsp->GetStatus() != ResultStatus::Success) {
return; return;
@ -46,12 +45,8 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_,
return pm.ParseControlNCA(*control_nca); return pm.ParseControlNCA(*control_nca);
}(); }();
if (title_id == 0) {
return;
}
secondary_loader = std::make_unique<AppLoader_NCA>( secondary_loader = std::make_unique<AppLoader_NCA>(
nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program)); nsp->GetNCAFile(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Program));
} }
} }
@ -68,10 +63,11 @@ FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& nsp_file) {
} }
// Non-Extracted Type case // Non-Extracted Type case
const auto program_id = nsp.GetProgramTitleID();
if (!nsp.IsExtractedType() && if (!nsp.IsExtractedType() &&
nsp.GetNCA(nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program) != nullptr && nsp.GetNCA(program_id, FileSys::ContentRecordType::Program) != nullptr &&
AppLoader_NCA::IdentifyType(nsp.GetNCAFile( AppLoader_NCA::IdentifyType(
nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program)) == FileType::NCA) { nsp.GetNCAFile(program_id, FileSys::ContentRecordType::Program)) == FileType::NCA) {
return FileType::NSP; return FileType::NSP;
} }
} }
@ -84,6 +80,8 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::S
return {ResultStatus::ErrorAlreadyLoaded, {}}; return {ResultStatus::ErrorAlreadyLoaded, {}};
} }
const auto title_id = nsp->GetProgramTitleID();
if (!nsp->IsExtractedType() && title_id == 0) { if (!nsp->IsExtractedType() && title_id == 0) {
return {ResultStatus::ErrorNSPMissingProgramNCA, {}}; return {ResultStatus::ErrorNSPMissingProgramNCA, {}};
} }
@ -93,7 +91,7 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::S
return {nsp_status, {}}; return {nsp_status, {}};
} }
const auto nsp_program_status = nsp->GetProgramStatus(title_id); const auto nsp_program_status = nsp->GetProgramStatus();
if (nsp_program_status != ResultStatus::Success) { if (nsp_program_status != ResultStatus::Success) {
return {nsp_program_status, {}}; return {nsp_program_status, {}};
} }
@ -134,8 +132,8 @@ ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& out_file) {
return ResultStatus::ErrorNoPackedUpdate; return ResultStatus::ErrorNoPackedUpdate;
} }
const auto read = const auto read = nsp->GetNCAFile(FileSys::GetUpdateTitleID(nsp->GetProgramTitleID()),
nsp->GetNCAFile(FileSys::GetUpdateTitleID(title_id), FileSys::ContentRecordType::Program); FileSys::ContentRecordType::Program);
if (read == nullptr) { if (read == nullptr) {
return ResultStatus::ErrorNoPackedUpdate; return ResultStatus::ErrorNoPackedUpdate;
@ -151,11 +149,15 @@ ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& out_file) {
} }
ResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) { ResultStatus AppLoader_NSP::ReadProgramId(u64& out_program_id) {
if (title_id == 0) { out_program_id = nsp->GetProgramTitleID();
if (out_program_id == 0) {
return ResultStatus::ErrorNotInitialized; return ResultStatus::ErrorNotInitialized;
} }
return ResultStatus::Success;
}
out_program_id = title_id; ResultStatus AppLoader_NSP::ReadProgramIds(std::vector<u64>& out_program_ids) {
out_program_ids = nsp->GetProgramTitleIDs();
return ResultStatus::Success; return ResultStatus::Success;
} }

View File

@ -28,7 +28,7 @@ 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, u64 program_id,
std::size_t program_index); std::size_t program_index);
~AppLoader_NSP() override; ~AppLoader_NSP() override;
@ -51,6 +51,7 @@ public:
u64 ReadRomFSIVFCOffset() const override; u64 ReadRomFSIVFCOffset() const override;
ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override; ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override;
ResultStatus ReadProgramId(u64& out_program_id) override; ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadProgramIds(std::vector<u64>& out_program_ids) override;
ResultStatus ReadIcon(std::vector<u8>& buffer) override; ResultStatus ReadIcon(std::vector<u8>& buffer) override;
ResultStatus ReadTitle(std::string& title) override; ResultStatus ReadTitle(std::string& title) override;
ResultStatus ReadControlData(FileSys::NACP& nacp) override; ResultStatus ReadControlData(FileSys::NACP& nacp) override;
@ -67,7 +68,6 @@ private:
FileSys::VirtualFile icon_file; FileSys::VirtualFile icon_file;
std::unique_ptr<FileSys::NACP> nacp_file; std::unique_ptr<FileSys::NACP> nacp_file;
u64 title_id;
}; };
} // namespace Loader } // namespace Loader

View File

@ -22,9 +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, u64 program_id,
std::size_t program_index) std::size_t program_index)
: AppLoader(file_), xci(std::make_unique<FileSys::XCI>(file_, program_index)), : AppLoader(file_), xci(std::make_unique<FileSys::XCI>(file_, program_id, 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;
@ -121,6 +121,11 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) {
return nca_loader->ReadProgramId(out_program_id); return nca_loader->ReadProgramId(out_program_id);
} }
ResultStatus AppLoader_XCI::ReadProgramIds(std::vector<u64>& out_program_ids) {
out_program_ids = xci->GetProgramTitleIDs();
return ResultStatus::Success;
}
ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) { ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) {
if (icon_file == nullptr) { if (icon_file == nullptr) {
return ResultStatus::ErrorNoControl; return ResultStatus::ErrorNoControl;
@ -149,8 +154,9 @@ ResultStatus AppLoader_XCI::ReadControlData(FileSys::NACP& control) {
} }
ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& out_file) { ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& out_file) {
const auto nca = xci->GetSecurePartitionNSP()->GetNCA(xci->GetProgramTitleID(), const auto nca =
FileSys::ContentRecordType::HtmlDocument); xci->GetSecurePartitionNSP()->GetNCA(xci->GetSecurePartitionNSP()->GetProgramTitleID(),
FileSys::ContentRecordType::HtmlDocument);
if (xci->GetStatus() != ResultStatus::Success || nca == nullptr) { if (xci->GetStatus() != ResultStatus::Success || nca == nullptr) {
return ResultStatus::ErrorXCIMissingPartition; return ResultStatus::ErrorXCIMissingPartition;
} }

View File

@ -28,7 +28,7 @@ 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, u64 program_id,
std::size_t program_index); std::size_t program_index);
~AppLoader_XCI() override; ~AppLoader_XCI() override;
@ -51,6 +51,7 @@ public:
u64 ReadRomFSIVFCOffset() const override; u64 ReadRomFSIVFCOffset() const override;
ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override; ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override;
ResultStatus ReadProgramId(u64& out_program_id) override; ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadProgramIds(std::vector<u64>& out_program_ids) override;
ResultStatus ReadIcon(std::vector<u8>& buffer) override; ResultStatus ReadIcon(std::vector<u8>& buffer) override;
ResultStatus ReadTitle(std::string& title) override; ResultStatus ReadTitle(std::string& title) override;
ResultStatus ReadControlData(FileSys::NACP& control) override; ResultStatus ReadControlData(FileSys::NACP& control) override;

View File

@ -297,7 +297,7 @@ struct fmt::formatter<Shader::Backend::GLASM::ScalarF64> {
case Shader::Backend::GLASM::Type::U32: case Shader::Backend::GLASM::Type::U32:
break; break;
case Shader::Backend::GLASM::Type::U64: case Shader::Backend::GLASM::Type::U64:
return format_to(ctx.out(), "{}", Common::BitCast<f64>(value.imm_u64)); return fmt::format_to(ctx.out(), "{}", Common::BitCast<f64>(value.imm_u64));
} }
throw Shader::InvalidArgument("Invalid value type {}", value.type); throw Shader::InvalidArgument("Invalid value type {}", value.type);
} }

View File

@ -6,6 +6,8 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector>
#include <fmt/format.h> #include <fmt/format.h>
#include "shader_recompiler/backend/glsl/var_alloc.h" #include "shader_recompiler/backend/glsl/var_alloc.h"

View File

@ -3,7 +3,6 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <algorithm> #include <algorithm>
#include <bit>
#include <memory> #include <memory>
#include <ranges> #include <ranges>
#include <vector> #include <vector>
@ -144,7 +143,9 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
program.is_geometry_passthrough = sph.common0.geometry_passthrough != 0; program.is_geometry_passthrough = sph.common0.geometry_passthrough != 0;
if (program.is_geometry_passthrough) { if (program.is_geometry_passthrough) {
const auto& mask{env.GpPassthroughMask()}; const auto& mask{env.GpPassthroughMask()};
program.info.passthrough.mask |= ~std::bit_cast<std::bitset<256>>(mask); for (size_t i = 0; i < program.info.passthrough.mask.size(); ++i) {
program.info.passthrough.mask[i] = ((mask[i / 32] >> (i % 32)) & 1) == 0;
}
} }
break; break;
} }

View File

@ -24,8 +24,8 @@
#include "video_core/host_shaders/opengl_present_frag.h" #include "video_core/host_shaders/opengl_present_frag.h"
#include "video_core/host_shaders/opengl_present_vert.h" #include "video_core/host_shaders/opengl_present_vert.h"
#include "video_core/renderer_opengl/gl_rasterizer.h" #include "video_core/renderer_opengl/gl_rasterizer.h"
#include "video_core/renderer_opengl/gl_shader_util.h"
#include "video_core/renderer_opengl/gl_shader_manager.h" #include "video_core/renderer_opengl/gl_shader_manager.h"
#include "video_core/renderer_opengl/gl_shader_util.h"
#include "video_core/renderer_opengl/renderer_opengl.h" #include "video_core/renderer_opengl/renderer_opengl.h"
#include "video_core/textures/decoders.h" #include "video_core/textures/decoders.h"

View File

@ -97,14 +97,19 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
Core::Frontend::EmuWindow& emu_window, Core::Frontend::EmuWindow& emu_window,
Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_,
std::unique_ptr<Core::Frontend::GraphicsContext> context_) try std::unique_ptr<Core::Frontend::GraphicsContext> context_) try
: RendererBase(emu_window, std::move(context_)), telemetry_session(telemetry_session_), : RendererBase(emu_window, std::move(context_)),
cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary()), telemetry_session(telemetry_session_),
cpu_memory(cpu_memory_),
gpu(gpu_),
library(OpenLibrary()),
instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
true, Settings::values.renderer_debug.GetValue())), true, Settings::values.renderer_debug.GetValue())),
debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
surface(CreateSurface(instance, render_window)), surface(CreateSurface(instance, render_window)),
device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false), device(CreateDevice(instance, dld, *surface)),
state_tracker(gpu), scheduler(device, state_tracker), memory_allocator(device, false),
state_tracker(gpu),
scheduler(device, state_tracker),
swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width,
render_window.GetFramebufferLayout().height, false), render_window.GetFramebufferLayout().height, false),
blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, scheduler, blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, scheduler,

View File

@ -503,9 +503,8 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
vertex_attributes.push_back({ vertex_attributes.push_back({
.location = static_cast<u32>(index), .location = static_cast<u32>(index),
.binding = 0, .binding = 0,
.format = type == 1 ? VK_FORMAT_R32_SFLOAT .format = type == 1 ? VK_FORMAT_R32_SFLOAT
: type == 2 ? VK_FORMAT_R32_SINT : type == 2 ? VK_FORMAT_R32_SINT : VK_FORMAT_R32_UINT,
: VK_FORMAT_R32_UINT,
.offset = 0, .offset = 0,
}); });
} }

View File

@ -839,7 +839,6 @@ void Config::ReadRendererValues() {
ReadGlobalSetting(Settings::values.use_nvdec_emulation); ReadGlobalSetting(Settings::values.use_nvdec_emulation);
ReadGlobalSetting(Settings::values.accelerate_astc); ReadGlobalSetting(Settings::values.accelerate_astc);
ReadGlobalSetting(Settings::values.use_vsync); ReadGlobalSetting(Settings::values.use_vsync);
ReadGlobalSetting(Settings::values.disable_fps_limit);
ReadGlobalSetting(Settings::values.shader_backend); ReadGlobalSetting(Settings::values.shader_backend);
ReadGlobalSetting(Settings::values.use_asynchronous_shaders); ReadGlobalSetting(Settings::values.use_asynchronous_shaders);
ReadGlobalSetting(Settings::values.use_fast_gpu_time); ReadGlobalSetting(Settings::values.use_fast_gpu_time);
@ -1371,7 +1370,6 @@ void Config::SaveRendererValues() {
WriteGlobalSetting(Settings::values.use_nvdec_emulation); WriteGlobalSetting(Settings::values.use_nvdec_emulation);
WriteGlobalSetting(Settings::values.accelerate_astc); WriteGlobalSetting(Settings::values.accelerate_astc);
WriteGlobalSetting(Settings::values.use_vsync); WriteGlobalSetting(Settings::values.use_vsync);
WriteGlobalSetting(Settings::values.disable_fps_limit);
WriteSetting(QString::fromStdString(Settings::values.shader_backend.GetLabel()), WriteSetting(QString::fromStdString(Settings::values.shader_backend.GetLabel()),
static_cast<u32>(Settings::values.shader_backend.GetValue(global)), static_cast<u32>(Settings::values.shader_backend.GetValue(global)),
static_cast<u32>(Settings::values.shader_backend.GetDefault()), static_cast<u32>(Settings::values.shader_backend.GetDefault()),

View File

@ -27,7 +27,6 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {
ui->anisotropic_filtering_combobox->setEnabled(runtime_lock); ui->anisotropic_filtering_combobox->setEnabled(runtime_lock);
ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue()); ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue());
ui->disable_fps_limit->setChecked(Settings::values.disable_fps_limit.GetValue());
ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue()); ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue());
ui->use_caches_gc->setChecked(Settings::values.use_caches_gc.GetValue()); ui->use_caches_gc->setChecked(Settings::values.use_caches_gc.GetValue());
ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue()); ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue());
@ -57,8 +56,6 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
ui->anisotropic_filtering_combobox); ui->anisotropic_filtering_combobox);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.disable_fps_limit,
ui->disable_fps_limit, disable_fps_limit);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders, ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
ui->use_asynchronous_shaders, ui->use_asynchronous_shaders,
use_asynchronous_shaders); use_asynchronous_shaders);
@ -99,7 +96,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
if (Settings::IsConfiguringGlobal()) { if (Settings::IsConfiguringGlobal()) {
ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal()); ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal());
ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal()); ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal());
ui->disable_fps_limit->setEnabled(Settings::values.disable_fps_limit.UsingGlobal());
ui->use_asynchronous_shaders->setEnabled( ui->use_asynchronous_shaders->setEnabled(
Settings::values.use_asynchronous_shaders.UsingGlobal()); Settings::values.use_asynchronous_shaders.UsingGlobal());
ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal()); ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal());
@ -111,8 +107,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
} }
ConfigurationShared::SetColoredTristate(ui->use_vsync, Settings::values.use_vsync, use_vsync); ConfigurationShared::SetColoredTristate(ui->use_vsync, Settings::values.use_vsync, use_vsync);
ConfigurationShared::SetColoredTristate(ui->disable_fps_limit,
Settings::values.disable_fps_limit, disable_fps_limit);
ConfigurationShared::SetColoredTristate(ui->use_asynchronous_shaders, ConfigurationShared::SetColoredTristate(ui->use_asynchronous_shaders,
Settings::values.use_asynchronous_shaders, Settings::values.use_asynchronous_shaders,
use_asynchronous_shaders); use_asynchronous_shaders);

View File

@ -35,7 +35,6 @@ private:
std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui; std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui;
ConfigurationShared::CheckState use_vsync; ConfigurationShared::CheckState use_vsync;
ConfigurationShared::CheckState disable_fps_limit;
ConfigurationShared::CheckState use_asynchronous_shaders; ConfigurationShared::CheckState use_asynchronous_shaders;
ConfigurationShared::CheckState use_fast_gpu_time; ConfigurationShared::CheckState use_fast_gpu_time;
ConfigurationShared::CheckState use_caches_gc; ConfigurationShared::CheckState use_caches_gc;

View File

@ -76,24 +76,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="disable_fps_limit">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>
&lt;html&gt;&lt;head/&gt;&lt;body&gt;
&lt;p&gt;Presents guest frames as they become available, disabling the FPS limit in most titles.&lt;/p&gt;
&lt;p&gt;NOTE: Will cause instabilities.&lt;/p&gt;
&lt;/body&gt;&lt;/html&gt;
</string>
</property>
<property name="text">
<string>Disable framerate limit (experimental)</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QCheckBox" name="use_asynchronous_shaders"> <widget class="QCheckBox" name="use_asynchronous_shaders">
<property name="toolTip"> <property name="toolTip">

View File

@ -404,9 +404,11 @@ void GameList::ValidateEntry(const QModelIndex& item) {
return; return;
} }
const auto title_id = selected.data(GameListItemPath::ProgramIdRole).toULongLong();
// Users usually want to run a different game after closing one // Users usually want to run a different game after closing one
search_field->clear(); search_field->clear();
emit GameChosen(file_path); emit GameChosen(file_path, title_id);
break; break;
} }
case GameListItemType::AddDir: case GameListItemType::AddDir:
@ -518,9 +520,11 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
QMenu* remove_menu = context_menu.addMenu(tr("Remove")); QMenu* remove_menu = context_menu.addMenu(tr("Remove"));
QAction* remove_update = remove_menu->addAction(tr("Remove Installed Update")); QAction* remove_update = remove_menu->addAction(tr("Remove Installed Update"));
QAction* remove_dlc = remove_menu->addAction(tr("Remove All Installed DLC")); QAction* remove_dlc = remove_menu->addAction(tr("Remove All Installed DLC"));
QAction* remove_shader_cache = remove_menu->addAction(tr("Remove Shader Cache"));
QAction* remove_custom_config = remove_menu->addAction(tr("Remove Custom Configuration")); QAction* remove_custom_config = remove_menu->addAction(tr("Remove Custom Configuration"));
QAction* remove_gl_shader_cache = remove_menu->addAction(tr("Remove OpenGL Shader Cache"));
QAction* remove_vk_shader_cache = remove_menu->addAction(tr("Remove Vulkan Shader Cache"));
remove_menu->addSeparator(); remove_menu->addSeparator();
QAction* remove_shader_cache = remove_menu->addAction(tr("Remove All Shader Caches"));
QAction* remove_all_content = remove_menu->addAction(tr("Remove All Installed Contents")); QAction* remove_all_content = remove_menu->addAction(tr("Remove All Installed Contents"));
QMenu* dump_romfs_menu = context_menu.addMenu(tr("Dump RomFS")); QMenu* dump_romfs_menu = context_menu.addMenu(tr("Dump RomFS"));
QAction* dump_romfs = dump_romfs_menu->addAction(tr("Dump RomFS")); QAction* dump_romfs = dump_romfs_menu->addAction(tr("Dump RomFS"));
@ -538,6 +542,8 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
open_transferable_shader_cache->setVisible(program_id != 0); open_transferable_shader_cache->setVisible(program_id != 0);
remove_update->setVisible(program_id != 0); remove_update->setVisible(program_id != 0);
remove_dlc->setVisible(program_id != 0); remove_dlc->setVisible(program_id != 0);
remove_gl_shader_cache->setVisible(program_id != 0);
remove_vk_shader_cache->setVisible(program_id != 0);
remove_shader_cache->setVisible(program_id != 0); remove_shader_cache->setVisible(program_id != 0);
remove_all_content->setVisible(program_id != 0); remove_all_content->setVisible(program_id != 0);
auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
@ -548,10 +554,10 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path); emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path);
}); });
connect(start_game, &QAction::triggered, [this, path]() { connect(start_game, &QAction::triggered, [this, path]() {
emit BootGame(QString::fromStdString(path), 0, StartGameType::Normal); emit BootGame(QString::fromStdString(path), 0, 0, StartGameType::Normal);
}); });
connect(start_game_global, &QAction::triggered, [this, path]() { connect(start_game_global, &QAction::triggered, [this, path]() {
emit BootGame(QString::fromStdString(path), 0, StartGameType::Global); emit BootGame(QString::fromStdString(path), 0, 0, StartGameType::Global);
}); });
connect(open_mod_location, &QAction::triggered, [this, program_id, path]() { connect(open_mod_location, &QAction::triggered, [this, program_id, path]() {
emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path); emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path);
@ -567,8 +573,14 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
connect(remove_dlc, &QAction::triggered, [this, program_id]() { connect(remove_dlc, &QAction::triggered, [this, program_id]() {
emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::AddOnContent); emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::AddOnContent);
}); });
connect(remove_gl_shader_cache, &QAction::triggered, [this, program_id, path]() {
emit RemoveFileRequested(program_id, GameListRemoveTarget::GlShaderCache, path);
});
connect(remove_vk_shader_cache, &QAction::triggered, [this, program_id, path]() {
emit RemoveFileRequested(program_id, GameListRemoveTarget::VkShaderCache, path);
});
connect(remove_shader_cache, &QAction::triggered, [this, program_id, path]() { connect(remove_shader_cache, &QAction::triggered, [this, program_id, path]() {
emit RemoveFileRequested(program_id, GameListRemoveTarget::ShaderCache, path); emit RemoveFileRequested(program_id, GameListRemoveTarget::AllShaderCache, path);
}); });
connect(remove_custom_config, &QAction::triggered, [this, program_id, path]() { connect(remove_custom_config, &QAction::triggered, [this, program_id, path]() {
emit RemoveFileRequested(program_id, GameListRemoveTarget::CustomConfiguration, path); emit RemoveFileRequested(program_id, GameListRemoveTarget::CustomConfiguration, path);

View File

@ -41,7 +41,9 @@ enum class GameListOpenTarget {
}; };
enum class GameListRemoveTarget { enum class GameListRemoveTarget {
ShaderCache, GlShaderCache,
VkShaderCache,
AllShaderCache,
CustomConfiguration, CustomConfiguration,
}; };
@ -88,8 +90,9 @@ public:
static const QStringList supported_file_extensions; static const QStringList supported_file_extensions;
signals: signals:
void BootGame(const QString& game_path, std::size_t program_index, StartGameType type); void BootGame(const QString& game_path, u64 program_id, std::size_t program_index,
void GameChosen(const QString& game_path); StartGameType type);
void GameChosen(const QString& game_path, const u64 title_id = 0);
void ShouldCancelWorker(); void ShouldCancelWorker();
void OpenFolderRequested(u64 program_id, GameListOpenTarget target, void OpenFolderRequested(u64 program_id, GameListOpenTarget target,
const std::string& game_path); const std::string& game_path);

View File

@ -336,18 +336,44 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa
} }
} }
} else { } else {
std::vector<u8> icon; std::vector<u64> program_ids;
[[maybe_unused]] const auto res1 = loader->ReadIcon(icon); loader->ReadProgramIds(program_ids);
std::string name = " "; if (res2 == Loader::ResultStatus::Success && program_ids.size() > 1 &&
[[maybe_unused]] const auto res3 = loader->ReadTitle(name); (file_type == Loader::FileType::XCI || file_type == Loader::FileType::NSP)) {
for (const auto id : program_ids) {
loader = Loader::GetLoader(system, file, id);
if (!loader) {
continue;
}
const FileSys::PatchManager patch{program_id, system.GetFileSystemController(), std::vector<u8> icon;
system.GetContentProvider()}; [[maybe_unused]] const auto res1 = loader->ReadIcon(icon);
emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, program_id, std::string name = " ";
compatibility_list, patch), [[maybe_unused]] const auto res3 = loader->ReadTitle(name);
parent_dir);
const FileSys::PatchManager patch{id, system.GetFileSystemController(),
system.GetContentProvider()};
emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, id,
compatibility_list, patch),
parent_dir);
}
} else {
std::vector<u8> icon;
[[maybe_unused]] const auto res1 = loader->ReadIcon(icon);
std::string name = " ";
[[maybe_unused]] const auto res3 = loader->ReadTitle(name);
const FileSys::PatchManager patch{program_id, system.GetFileSystemController(),
system.GetContentProvider()};
emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader,
program_id, compatibility_list, patch),
parent_dir);
}
} }
} else if (is_dir) { } else if (is_dir) {
watch_list.append(QString::fromStdString(physical_name)); watch_list.append(QString::fromStdString(physical_name));

View File

@ -1208,7 +1208,7 @@ void GMainWindow::AllowOSSleep() {
#endif #endif
} }
bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) { bool GMainWindow::LoadROM(const QString& filename, u64 program_id, 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();
@ -1231,7 +1231,7 @@ bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) {
}); });
const Core::System::ResultStatus result{ const Core::System::ResultStatus result{
system.Load(*render_window, filename.toStdString(), program_index)}; system.Load(*render_window, filename.toStdString(), program_id, program_index)};
const auto drd_callout = (UISettings::values.callout_flags.GetValue() & const auto drd_callout = (UISettings::values.callout_flags.GetValue() &
static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0; static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0;
@ -1318,7 +1318,8 @@ void GMainWindow::SelectAndSetCurrentUser() {
Settings::values.current_user = dialog.GetIndex(); Settings::values.current_user = dialog.GetIndex();
} }
void GMainWindow::BootGame(const QString& filename, std::size_t program_index, StartGameType type) { void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t program_index,
StartGameType type) {
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
@ -1328,7 +1329,7 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index, S
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, program_index); const auto loader = Loader::GetLoader(system, v_file, program_id, 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) { type == StartGameType::Normal) {
@ -1342,6 +1343,9 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index, S
ConfigureVibration::SetAllVibrationDevices(); ConfigureVibration::SetAllVibrationDevices();
// Disable fps limit toggle when booting a new title
Settings::values.disable_fps_limit.SetValue(false);
// Save configurations // Save configurations
UpdateUISettings(); UpdateUISettings();
game_list->SaveInterfaceLayout(); game_list->SaveInterfaceLayout();
@ -1353,7 +1357,7 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index, S
SelectAndSetCurrentUser(); SelectAndSetCurrentUser();
} }
if (!LoadROM(filename, program_index)) if (!LoadROM(filename, program_id, program_index))
return; return;
// Create and start the emulation thread // Create and start the emulation thread
@ -1526,8 +1530,8 @@ void GMainWindow::UpdateRecentFiles() {
ui.menu_recent_files->setEnabled(num_recent_files != 0); ui.menu_recent_files->setEnabled(num_recent_files != 0);
} }
void GMainWindow::OnGameListLoadFile(QString game_path) { void GMainWindow::OnGameListLoadFile(QString game_path, u64 program_id) {
BootGame(game_path); BootGame(game_path, program_id);
} }
void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target,
@ -1632,9 +1636,9 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) {
const auto shader_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir); const auto shader_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir);
const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)}; const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)};
if (!Common::FS::Exists(shader_cache_folder_path)) { if (!Common::FS::CreateDirs(shader_cache_folder_path)) {
QMessageBox::warning(this, tr("Error Opening Transferable Shader Cache"), QMessageBox::warning(this, tr("Error Opening Transferable Shader Cache"),
tr("A shader cache for this title does not exist.")); tr("Filed to create the shader cache directory for this title."));
return; return;
} }
const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)}; const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)};
@ -1782,8 +1786,12 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget targ
const std::string& game_path) { const std::string& game_path) {
const QString question = [this, target] { const QString question = [this, target] {
switch (target) { switch (target) {
case GameListRemoveTarget::ShaderCache: case GameListRemoveTarget::GlShaderCache:
return tr("Delete Transferable Shader Cache?"); return tr("Delete OpenGL Transferable Shader Cache?");
case GameListRemoveTarget::VkShaderCache:
return tr("Delete Vulkan Transferable Shader Cache?");
case GameListRemoveTarget::AllShaderCache:
return tr("Delete All Transferable Shader Caches?");
case GameListRemoveTarget::CustomConfiguration: case GameListRemoveTarget::CustomConfiguration:
return tr("Remove Custom Game Configuration?"); return tr("Remove Custom Game Configuration?");
default: default:
@ -1797,8 +1805,12 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget targ
} }
switch (target) { switch (target) {
case GameListRemoveTarget::ShaderCache: case GameListRemoveTarget::GlShaderCache:
RemoveTransferableShaderCache(program_id); case GameListRemoveTarget::VkShaderCache:
RemoveTransferableShaderCache(program_id, target);
break;
case GameListRemoveTarget::AllShaderCache:
RemoveAllTransferableShaderCaches(program_id);
break; break;
case GameListRemoveTarget::CustomConfiguration: case GameListRemoveTarget::CustomConfiguration:
RemoveCustomConfiguration(program_id, game_path); RemoveCustomConfiguration(program_id, game_path);
@ -1806,18 +1818,27 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget targ
} }
} }
void GMainWindow::RemoveTransferableShaderCache(u64 program_id) { void GMainWindow::RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target) {
const auto target_file_name = [target] {
switch (target) {
case GameListRemoveTarget::GlShaderCache:
return "opengl.bin";
case GameListRemoveTarget::VkShaderCache:
return "vulkan.bin";
default:
return "";
}
}();
const auto shader_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir); const auto shader_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir);
const auto transferable_shader_cache_file_path = const auto shader_cache_folder_path = shader_cache_dir / fmt::format("{:016x}", program_id);
shader_cache_dir / "opengl" / "transferable" / fmt::format("{:016X}.bin", program_id); const auto target_file = shader_cache_folder_path / target_file_name;
if (!Common::FS::Exists(transferable_shader_cache_file_path)) { if (!Common::FS::Exists(target_file)) {
QMessageBox::warning(this, tr("Error Removing Transferable Shader Cache"), QMessageBox::warning(this, tr("Error Removing Transferable Shader Cache"),
tr("A shader cache for this title does not exist.")); tr("A shader cache for this title does not exist."));
return; return;
} }
if (Common::FS::RemoveFile(target_file)) {
if (Common::FS::RemoveFile(transferable_shader_cache_file_path)) {
QMessageBox::information(this, tr("Successfully Removed"), QMessageBox::information(this, tr("Successfully Removed"),
tr("Successfully removed the transferable shader cache.")); tr("Successfully removed the transferable shader cache."));
} else { } else {
@ -1826,6 +1847,24 @@ void GMainWindow::RemoveTransferableShaderCache(u64 program_id) {
} }
} }
void GMainWindow::RemoveAllTransferableShaderCaches(u64 program_id) {
const auto shader_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ShaderDir);
const auto program_shader_cache_dir = shader_cache_dir / fmt::format("{:016x}", program_id);
if (!Common::FS::Exists(program_shader_cache_dir)) {
QMessageBox::warning(this, tr("Error Removing Transferable Shader Caches"),
tr("A shader cache for this title does not exist."));
return;
}
if (Common::FS::RemoveDirRecursively(program_shader_cache_dir)) {
QMessageBox::information(this, tr("Successfully Removed"),
tr("Successfully removed the transferable shader caches."));
} else {
QMessageBox::warning(this, tr("Error Removing Transferable Shader Caches"),
tr("Failed to remove the transferable shader cache directory."));
}
}
void GMainWindow::RemoveCustomConfiguration(u64 program_id, const std::string& game_path) { void GMainWindow::RemoveCustomConfiguration(u64 program_id, const std::string& game_path) {
const auto file_path = std::filesystem::path(Common::FS::ToU8String(game_path)); const auto file_path = std::filesystem::path(Common::FS::ToU8String(game_path));
const auto config_file_name = const auto config_file_name =
@ -2408,7 +2447,7 @@ void GMainWindow::OnLoadComplete() {
void GMainWindow::OnExecuteProgram(std::size_t program_index) { void GMainWindow::OnExecuteProgram(std::size_t program_index) {
ShutdownGame(); ShutdownGame();
BootGame(last_filename_booted, program_index); BootGame(last_filename_booted, 0, program_index);
} }
void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) {
@ -2876,7 +2915,12 @@ void GMainWindow::UpdateStatusBar() {
} else { } else {
emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0)); emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
} }
game_fps_label->setText(tr("Game: %1 FPS").arg(results.average_game_fps, 0, 'f', 0)); if (Settings::values.disable_fps_limit) {
game_fps_label->setText(
tr("Game: %1 FPS (Limit off)").arg(results.average_game_fps, 0, 'f', 0));
} else {
game_fps_label->setText(tr("Game: %1 FPS").arg(results.average_game_fps, 0, 'f', 0));
}
emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2)); emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue()); emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue());

View File

@ -186,8 +186,8 @@ private:
void PreventOSSleep(); void PreventOSSleep();
void AllowOSSleep(); void AllowOSSleep();
bool LoadROM(const QString& filename, std::size_t program_index); bool LoadROM(const QString& filename, u64 program_id, std::size_t program_index);
void BootGame(const QString& filename, std::size_t program_index = 0, 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);
void ShutdownGame(); void ShutdownGame();
@ -238,7 +238,7 @@ private slots:
void OnOpenQuickstartGuide(); void OnOpenQuickstartGuide();
void OnOpenFAQ(); void OnOpenFAQ();
/// Called whenever a user selects a game in the game list widget. /// Called whenever a user selects a game in the game list widget.
void OnGameListLoadFile(QString game_path); void OnGameListLoadFile(QString game_path, u64 program_id);
void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target,
const std::string& game_path); const std::string& game_path);
void OnTransferableShaderCacheOpenFile(u64 program_id); void OnTransferableShaderCacheOpenFile(u64 program_id);
@ -282,7 +282,8 @@ private:
void RemoveBaseContent(u64 program_id, const QString& entry_type); void RemoveBaseContent(u64 program_id, const QString& entry_type);
void RemoveUpdateContent(u64 program_id, const QString& entry_type); void RemoveUpdateContent(u64 program_id, const QString& entry_type);
void RemoveAddOnContent(u64 program_id, const QString& entry_type); void RemoveAddOnContent(u64 program_id, const QString& entry_type);
void RemoveTransferableShaderCache(u64 program_id); void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target);
void RemoveAllTransferableShaderCaches(u64 program_id);
void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); void RemoveCustomConfiguration(u64 program_id, const std::string& game_path);
std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id); std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id);
InstallResult InstallNSPXCI(const QString& filename); InstallResult InstallNSPXCI(const QString& filename);