Compare commits
30 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab2180e808 | ||
|
|
07073734ed | ||
|
|
16f983d33a | ||
|
|
ffc78ce9c1 | ||
|
|
f85bbf3a8f | ||
|
|
b405a81a9c | ||
|
|
053860d9cb | ||
|
|
41f4edd256 | ||
|
|
efc449ca26 | ||
|
|
03a7131563 | ||
|
|
b727b6784f | ||
|
|
9e7f41cec6 | ||
|
|
29c39838fe | ||
|
|
7850dd0a76 | ||
|
|
a3ce26ae01 | ||
|
|
6d9f347e22 | ||
|
|
cb08e5bdd2 | ||
|
|
39cd8c3f02 | ||
|
|
f785933125 | ||
|
|
0e6ba0cd0d | ||
|
|
d3748cad73 | ||
|
|
48259de0c1 | ||
|
|
604ff1f178 | ||
|
|
718c272421 | ||
|
|
15ed73a6eb | ||
|
|
38a30f2255 | ||
|
|
91d5cef90e | ||
|
|
32f119c37a | ||
|
|
7dfd2715b7 | ||
|
|
5a45d295da |
@@ -13,7 +13,7 @@ project(yuzu)
|
||||
option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF)
|
||||
# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
|
||||
option(YUZU_ALLOW_SYSTEM_SDL2 "Try using system SDL2 before fallling back to one from externals" OFF)
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" ON "ENABLE_SDL2;NOT MSVC" OFF)
|
||||
|
||||
option(ENABLE_QT "Enable the Qt frontend" ON)
|
||||
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
|
||||
@@ -393,26 +393,20 @@ if (ENABLE_SDL2)
|
||||
add_library(SDL2 INTERFACE)
|
||||
target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARY}")
|
||||
target_include_directories(SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
|
||||
elseif (YUZU_USE_EXTERNAL_SDL2)
|
||||
message(STATUS "Using SDL2 from externals.")
|
||||
else()
|
||||
if (YUZU_ALLOW_SYSTEM_SDL2)
|
||||
find_package(SDL2 2.0.15 QUIET)
|
||||
find_package(SDL2 2.0.15 REQUIRED)
|
||||
|
||||
if (SDL2_FOUND)
|
||||
# Some installations don't set SDL2_LIBRARIES
|
||||
if("${SDL2_LIBRARIES}" STREQUAL "")
|
||||
message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2")
|
||||
set(SDL2_LIBRARIES "SDL2::SDL2")
|
||||
endif()
|
||||
|
||||
include_directories(SYSTEM ${SDL2_INCLUDE_DIRS})
|
||||
add_library(SDL2 INTERFACE)
|
||||
target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")
|
||||
else()
|
||||
message(STATUS "SDL2 2.0.15 or newer not found, falling back to externals.")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Using SDL2 from externals.")
|
||||
# Some installations don't set SDL2_LIBRARIES
|
||||
if("${SDL2_LIBRARIES}" STREQUAL "")
|
||||
message(WARNING "SDL2_LIBRARIES wasn't set, manually setting to SDL2::SDL2")
|
||||
set(SDL2_LIBRARIES "SDL2::SDL2")
|
||||
endif()
|
||||
|
||||
include_directories(SYSTEM ${SDL2_INCLUDE_DIRS})
|
||||
add_library(SDL2 INTERFACE)
|
||||
target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
2
externals/CMakeLists.txt
vendored
2
externals/CMakeLists.txt
vendored
@@ -51,7 +51,7 @@ if (NOT LIBUSB_FOUND OR YUZU_USE_BUNDLED_LIBUSB)
|
||||
endif()
|
||||
|
||||
# SDL2
|
||||
if (NOT SDL2_FOUND AND ENABLE_SDL2)
|
||||
if (YUZU_USE_EXTERNAL_SDL2)
|
||||
if (NOT WIN32)
|
||||
# Yuzu itself needs: Events Joystick Haptic Sensor Timers Audio
|
||||
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
|
||||
|
||||
@@ -216,9 +216,9 @@ struct System::Impl {
|
||||
}
|
||||
|
||||
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),
|
||||
program_index);
|
||||
program_id, program_index);
|
||||
|
||||
if (!app_loader) {
|
||||
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
|
||||
@@ -269,11 +269,10 @@ struct System::Impl {
|
||||
}
|
||||
}
|
||||
|
||||
u64 title_id{0};
|
||||
if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
|
||||
if (app_loader->ReadProgramId(program_id) != Loader::ResultStatus::Success) {
|
||||
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
|
||||
GetAndResetPerfStats();
|
||||
perf_stats->BeginSystemFrame();
|
||||
@@ -459,8 +458,8 @@ void System::Shutdown() {
|
||||
}
|
||||
|
||||
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
|
||||
std::size_t program_index) {
|
||||
return impl->Load(*this, emu_window, filepath, program_index);
|
||||
u64 program_id, std::size_t program_index) {
|
||||
return impl->Load(*this, emu_window, filepath, program_id, program_index);
|
||||
}
|
||||
|
||||
bool System::IsPoweredOn() const {
|
||||
|
||||
@@ -175,7 +175,7 @@ public:
|
||||
* @returns ResultStatus code, indicating if the operation succeeded.
|
||||
*/
|
||||
[[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
|
||||
|
||||
@@ -29,7 +29,7 @@ constexpr std::array partition_names{
|
||||
"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},
|
||||
partitions(partition_names.size()),
|
||||
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>(
|
||||
main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]),
|
||||
program_index);
|
||||
program_id, program_index);
|
||||
|
||||
ncas = secure_partition->GetNCAsCollapsed();
|
||||
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) {
|
||||
program_nca_status = Loader::ResultStatus::ErrorXCIMissingProgramNCA;
|
||||
}
|
||||
@@ -174,6 +174,10 @@ u64 XCI::GetProgramTitleID() const {
|
||||
return secure_partition->GetProgramTitleID();
|
||||
}
|
||||
|
||||
std::vector<u64> XCI::GetProgramTitleIDs() const {
|
||||
return secure_partition->GetProgramTitleIDs();
|
||||
}
|
||||
|
||||
u32 XCI::GetSystemUpdateVersion() {
|
||||
const auto update = GetPartition(XCIPartition::Update);
|
||||
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 {
|
||||
const auto iter =
|
||||
std::find_if(ncas.begin(), ncas.end(),
|
||||
[type](const std::shared_ptr<NCA>& nca) { return nca->GetType() == type; });
|
||||
const auto program_id = secure_partition->GetProgramTitleID();
|
||||
const auto iter = std::find_if(
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ enum class XCIPartition : u8 { Update, Normal, Secure, Logo };
|
||||
|
||||
class XCI : public ReadOnlyVfsDirectory {
|
||||
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;
|
||||
|
||||
Loader::ResultStatus GetStatus() const;
|
||||
@@ -104,6 +104,7 @@ public:
|
||||
VirtualFile GetLogoPartitionRaw() const;
|
||||
|
||||
u64 GetProgramTitleID() const;
|
||||
std::vector<u64> GetProgramTitleIDs() const;
|
||||
u32 GetSystemUpdateVersion();
|
||||
u64 GetSystemUpdateTitleID() const;
|
||||
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
NSP::NSP(VirtualFile file_, std::size_t program_index_)
|
||||
: file(std::move(file_)), program_index(program_index_), status{Loader::ResultStatus::Success},
|
||||
NSP::NSP(VirtualFile file_, u64 title_id_, std::size_t program_index_)
|
||||
: 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()} {
|
||||
if (pfs->GetStatus() != Loader::ResultStatus::Success) {
|
||||
status = pfs->GetStatus();
|
||||
@@ -46,60 +47,59 @@ Loader::ResultStatus NSP::GetStatus() const {
|
||||
return status;
|
||||
}
|
||||
|
||||
Loader::ResultStatus NSP::GetProgramStatus(u64 title_id) const {
|
||||
Loader::ResultStatus NSP::GetProgramStatus() const {
|
||||
if (IsExtractedType() && GetExeFS() != nullptr && FileSys::IsDirectoryExeFS(GetExeFS())) {
|
||||
return Loader::ResultStatus::Success;
|
||||
}
|
||||
|
||||
const auto iter = program_status.find(title_id);
|
||||
const auto iter = program_status.find(GetProgramTitleID());
|
||||
if (iter == program_status.end())
|
||||
return Loader::ResultStatus::ErrorNSPMissingProgramNCA;
|
||||
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 {
|
||||
if (IsExtractedType()) {
|
||||
if (GetExeFS() == nullptr || !IsDirectoryExeFS(GetExeFS())) {
|
||||
return 0;
|
||||
}
|
||||
return GetExtractedTitleID() + program_index;
|
||||
}
|
||||
|
||||
ProgramMetadata meta;
|
||||
if (meta.Load(GetExeFS()->GetFile("main.npdm")) == Loader::ResultStatus::Success) {
|
||||
return meta.GetTitleID();
|
||||
} else {
|
||||
return 0;
|
||||
auto program_id = expected_program_id;
|
||||
if (program_id == 0) {
|
||||
if (!program_status.empty()) {
|
||||
program_id = program_status.begin()->first;
|
||||
}
|
||||
}
|
||||
|
||||
const auto out = GetFirstTitleID();
|
||||
if ((out & 0x800) == 0)
|
||||
return out;
|
||||
program_id = program_id + program_index;
|
||||
if (program_status.find(program_id) != program_status.end()) {
|
||||
return program_id;
|
||||
}
|
||||
|
||||
const auto ids = GetTitleIDs();
|
||||
const auto ids = GetProgramTitleIDs();
|
||||
const auto iter =
|
||||
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 {
|
||||
if (IsExtractedType()) {
|
||||
return {GetProgramTitleID()};
|
||||
u64 NSP::GetExtractedTitleID() const {
|
||||
if (GetExeFS() == nullptr || !IsDirectoryExeFS(GetExeFS())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<u64> out;
|
||||
out.reserve(ncas.size());
|
||||
for (const auto& kv : ncas)
|
||||
out.push_back(kv.first);
|
||||
ProgramMetadata meta;
|
||||
if (meta.Load(GetExeFS()->GetFile("main.npdm")) == Loader::ResultStatus::Success) {
|
||||
return meta.GetTitleID();
|
||||
} 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;
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type, TitleType
|
||||
if (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())
|
||||
return nullptr;
|
||||
|
||||
@@ -160,7 +160,7 @@ std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type, TitleType
|
||||
VirtualFile NSP::GetNCAFile(u64 title_id, ContentRecordType type, TitleType title_type) const {
|
||||
if (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)
|
||||
return nca->GetBaseFile();
|
||||
return nullptr;
|
||||
@@ -286,6 +286,7 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
|
||||
|
||||
if (next_nca->GetType() == NCAContentType::Program) {
|
||||
program_status[next_nca->GetTitleId()] = next_nca->GetStatus();
|
||||
program_ids.insert(next_nca->GetTitleId() & 0xFFFFFFFFFFFFF000);
|
||||
}
|
||||
|
||||
if (next_nca->GetStatus() != Loader::ResultStatus::Success &&
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
@@ -27,15 +28,15 @@ enum class ContentRecordType : u8;
|
||||
|
||||
class NSP : public ReadOnlyVfsDirectory {
|
||||
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;
|
||||
|
||||
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.
|
||||
u64 GetFirstTitleID() const;
|
||||
u64 GetProgramTitleID() const;
|
||||
std::vector<u64> GetTitleIDs() const;
|
||||
u64 GetExtractedTitleID() const;
|
||||
std::vector<u64> GetProgramTitleIDs() const;
|
||||
|
||||
bool IsExtractedType() const;
|
||||
|
||||
@@ -69,6 +70,7 @@ private:
|
||||
|
||||
VirtualFile file;
|
||||
|
||||
const u64 expected_program_id;
|
||||
const std::size_t program_index;
|
||||
|
||||
bool extracted = false;
|
||||
@@ -78,6 +80,7 @@ private:
|
||||
std::shared_ptr<PartitionFilesystem> pfs;
|
||||
// Map title id -> {map type -> NCA}
|
||||
std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> ncas;
|
||||
std::set<u64> program_ids;
|
||||
std::vector<VirtualFile> ticket_files;
|
||||
|
||||
Core::Crypto::KeyManager& keys;
|
||||
|
||||
@@ -206,7 +206,8 @@ AppLoader::~AppLoader() = default;
|
||||
* @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,
|
||||
FileType type, std::size_t program_index) {
|
||||
FileType type, u64 program_id,
|
||||
std::size_t program_index) {
|
||||
switch (type) {
|
||||
// Standard ELF file format.
|
||||
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.
|
||||
case FileType::XCI:
|
||||
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.
|
||||
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
|
||||
case FileType::NSP:
|
||||
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
|
||||
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::size_t program_index) {
|
||||
u64 program_id, std::size_t program_index) {
|
||||
FileType type = IdentifyFile(file);
|
||||
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));
|
||||
|
||||
return GetFileLoader(system, std::move(file), type, program_index);
|
||||
return GetFileLoader(system, std::move(file), type, program_id, program_index);
|
||||
}
|
||||
|
||||
} // namespace Loader
|
||||
|
||||
@@ -226,6 +226,17 @@ public:
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
|
||||
@@ -23,10 +23,9 @@ namespace Loader {
|
||||
|
||||
AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_,
|
||||
const Service::FileSystem::FileSystemController& fsc,
|
||||
const FileSys::ContentProvider& content_provider,
|
||||
const FileSys::ContentProvider& content_provider, u64 program_id,
|
||||
std::size_t program_index)
|
||||
: AppLoader(file_), nsp(std::make_unique<FileSys::NSP>(file_, program_index)),
|
||||
title_id(nsp->GetProgramTitleID()) {
|
||||
: AppLoader(file_), nsp(std::make_unique<FileSys::NSP>(file_, program_id, program_index)) {
|
||||
|
||||
if (nsp->GetStatus() != ResultStatus::Success) {
|
||||
return;
|
||||
@@ -46,12 +45,8 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_,
|
||||
return pm.ParseControlNCA(*control_nca);
|
||||
}();
|
||||
|
||||
if (title_id == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
const auto program_id = nsp.GetProgramTitleID();
|
||||
if (!nsp.IsExtractedType() &&
|
||||
nsp.GetNCA(nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program) != nullptr &&
|
||||
AppLoader_NCA::IdentifyType(nsp.GetNCAFile(
|
||||
nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program)) == FileType::NCA) {
|
||||
nsp.GetNCA(program_id, FileSys::ContentRecordType::Program) != nullptr &&
|
||||
AppLoader_NCA::IdentifyType(
|
||||
nsp.GetNCAFile(program_id, FileSys::ContentRecordType::Program)) == FileType::NCA) {
|
||||
return FileType::NSP;
|
||||
}
|
||||
}
|
||||
@@ -84,6 +80,8 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::S
|
||||
return {ResultStatus::ErrorAlreadyLoaded, {}};
|
||||
}
|
||||
|
||||
const auto title_id = nsp->GetProgramTitleID();
|
||||
|
||||
if (!nsp->IsExtractedType() && title_id == 0) {
|
||||
return {ResultStatus::ErrorNSPMissingProgramNCA, {}};
|
||||
}
|
||||
@@ -93,7 +91,7 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::S
|
||||
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) {
|
||||
return {nsp_program_status, {}};
|
||||
}
|
||||
@@ -134,8 +132,8 @@ ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& out_file) {
|
||||
return ResultStatus::ErrorNoPackedUpdate;
|
||||
}
|
||||
|
||||
const auto read =
|
||||
nsp->GetNCAFile(FileSys::GetUpdateTitleID(title_id), FileSys::ContentRecordType::Program);
|
||||
const auto read = nsp->GetNCAFile(FileSys::GetUpdateTitleID(nsp->GetProgramTitleID()),
|
||||
FileSys::ContentRecordType::Program);
|
||||
|
||||
if (read == nullptr) {
|
||||
return ResultStatus::ErrorNoPackedUpdate;
|
||||
@@ -151,11 +149,15 @@ ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& out_file) {
|
||||
}
|
||||
|
||||
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::Success;
|
||||
}
|
||||
|
||||
out_program_id = title_id;
|
||||
ResultStatus AppLoader_NSP::ReadProgramIds(std::vector<u64>& out_program_ids) {
|
||||
out_program_ids = nsp->GetProgramTitleIDs();
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class AppLoader_NSP final : public AppLoader {
|
||||
public:
|
||||
explicit AppLoader_NSP(FileSys::VirtualFile file_,
|
||||
const Service::FileSystem::FileSystemController& fsc,
|
||||
const FileSys::ContentProvider& content_provider,
|
||||
const FileSys::ContentProvider& content_provider, u64 program_id,
|
||||
std::size_t program_index);
|
||||
~AppLoader_NSP() override;
|
||||
|
||||
@@ -51,6 +51,7 @@ public:
|
||||
u64 ReadRomFSIVFCOffset() const override;
|
||||
ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) 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 ReadTitle(std::string& title) override;
|
||||
ResultStatus ReadControlData(FileSys::NACP& nacp) override;
|
||||
@@ -67,7 +68,6 @@ private:
|
||||
|
||||
FileSys::VirtualFile icon_file;
|
||||
std::unique_ptr<FileSys::NACP> nacp_file;
|
||||
u64 title_id;
|
||||
};
|
||||
|
||||
} // namespace Loader
|
||||
|
||||
@@ -22,9 +22,9 @@ namespace Loader {
|
||||
|
||||
AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file_,
|
||||
const Service::FileSystem::FileSystemController& fsc,
|
||||
const FileSys::ContentProvider& content_provider,
|
||||
const FileSys::ContentProvider& content_provider, u64 program_id,
|
||||
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())) {
|
||||
if (xci->GetStatus() != ResultStatus::Success) {
|
||||
return;
|
||||
@@ -121,6 +121,11 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& 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) {
|
||||
if (icon_file == nullptr) {
|
||||
return ResultStatus::ErrorNoControl;
|
||||
@@ -149,8 +154,9 @@ ResultStatus AppLoader_XCI::ReadControlData(FileSys::NACP& control) {
|
||||
}
|
||||
|
||||
ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& out_file) {
|
||||
const auto nca = xci->GetSecurePartitionNSP()->GetNCA(xci->GetProgramTitleID(),
|
||||
FileSys::ContentRecordType::HtmlDocument);
|
||||
const auto nca =
|
||||
xci->GetSecurePartitionNSP()->GetNCA(xci->GetSecurePartitionNSP()->GetProgramTitleID(),
|
||||
FileSys::ContentRecordType::HtmlDocument);
|
||||
if (xci->GetStatus() != ResultStatus::Success || nca == nullptr) {
|
||||
return ResultStatus::ErrorXCIMissingPartition;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ class AppLoader_XCI final : public AppLoader {
|
||||
public:
|
||||
explicit AppLoader_XCI(FileSys::VirtualFile file_,
|
||||
const Service::FileSystem::FileSystemController& fsc,
|
||||
const FileSys::ContentProvider& content_provider,
|
||||
const FileSys::ContentProvider& content_provider, u64 program_id,
|
||||
std::size_t program_index);
|
||||
~AppLoader_XCI() override;
|
||||
|
||||
@@ -51,6 +51,7 @@ public:
|
||||
u64 ReadRomFSIVFCOffset() const override;
|
||||
ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) 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 ReadTitle(std::string& title) override;
|
||||
ResultStatus ReadControlData(FileSys::NACP& control) override;
|
||||
|
||||
@@ -10,15 +10,7 @@
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
// Ignore -Wimplicit-fallthrough due to https://github.com/libsdl-org/SDL/issues/4307
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#endif
|
||||
#include <SDL.h>
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/threadsafe_queue.h"
|
||||
|
||||
@@ -152,8 +152,8 @@ void BufferCacheRuntime::BindIndexBuffer(PrimitiveTopology topology, IndexFormat
|
||||
}
|
||||
if (vk_buffer == VK_NULL_HANDLE) {
|
||||
// Vulkan doesn't support null index buffers. Replace it with our own null buffer.
|
||||
ReserveNullIndexBuffer();
|
||||
vk_buffer = *null_index_buffer;
|
||||
ReserveNullBuffer();
|
||||
vk_buffer = *null_buffer;
|
||||
}
|
||||
scheduler.Record([vk_buffer, vk_offset, vk_index_type](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.BindIndexBuffer(vk_buffer, vk_offset, vk_index_type);
|
||||
@@ -195,6 +195,14 @@ void BufferCacheRuntime::BindTransformFeedbackBuffer(u32 index, VkBuffer buffer,
|
||||
// Already logged in the rasterizer
|
||||
return;
|
||||
}
|
||||
if (buffer == VK_NULL_HANDLE) {
|
||||
// Vulkan doesn't support null transform feedback buffers.
|
||||
// Replace it with our own null buffer.
|
||||
ReserveNullBuffer();
|
||||
buffer = *null_buffer;
|
||||
offset = 0;
|
||||
size = 0;
|
||||
}
|
||||
scheduler.Record([index, buffer, offset, size](vk::CommandBuffer cmdbuf) {
|
||||
const VkDeviceSize vk_offset = offset;
|
||||
const VkDeviceSize vk_size = size;
|
||||
@@ -279,11 +287,11 @@ void BufferCacheRuntime::ReserveQuadArrayLUT(u32 num_indices, bool wait_for_idle
|
||||
});
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::ReserveNullIndexBuffer() {
|
||||
if (null_index_buffer) {
|
||||
void BufferCacheRuntime::ReserveNullBuffer() {
|
||||
if (null_buffer) {
|
||||
return;
|
||||
}
|
||||
null_index_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{
|
||||
null_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
@@ -294,12 +302,12 @@ void BufferCacheRuntime::ReserveNullIndexBuffer() {
|
||||
.pQueueFamilyIndices = nullptr,
|
||||
});
|
||||
if (device.HasDebuggingToolAttached()) {
|
||||
null_index_buffer.SetObjectNameEXT("Null index buffer");
|
||||
null_buffer.SetObjectNameEXT("Null index buffer");
|
||||
}
|
||||
null_index_buffer_commit = memory_allocator.Commit(null_index_buffer, MemoryUsage::DeviceLocal);
|
||||
null_buffer_commit = memory_allocator.Commit(null_buffer, MemoryUsage::DeviceLocal);
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([buffer = *null_index_buffer](vk::CommandBuffer cmdbuf) {
|
||||
scheduler.Record([buffer = *null_buffer](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.FillBuffer(buffer, 0, VK_WHOLE_SIZE, 0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ private:
|
||||
|
||||
void ReserveQuadArrayLUT(u32 num_indices, bool wait_for_idle);
|
||||
|
||||
void ReserveNullIndexBuffer();
|
||||
void ReserveNullBuffer();
|
||||
|
||||
const Device& device;
|
||||
MemoryAllocator& memory_allocator;
|
||||
@@ -105,8 +105,8 @@ private:
|
||||
VkIndexType quad_array_lut_index_type{};
|
||||
u32 current_num_indices = 0;
|
||||
|
||||
vk::Buffer null_index_buffer;
|
||||
MemoryCommit null_index_buffer_commit;
|
||||
vk::Buffer null_buffer;
|
||||
MemoryCommit null_buffer_commit;
|
||||
|
||||
Uint8Pass uint8_pass;
|
||||
QuadIndexedPass quad_index_pass;
|
||||
|
||||
@@ -374,20 +374,20 @@ void ASTCDecoderPass::MakeDataBuffer() {
|
||||
|
||||
scheduler.Record([src = staging_ref.buffer, offset = staging_ref.offset, dst = *data_buffer,
|
||||
TOTAL_BUFFER_SIZE](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.CopyBuffer(src, dst,
|
||||
VkBufferCopy{
|
||||
.srcOffset = offset,
|
||||
.dstOffset = 0,
|
||||
.size = TOTAL_BUFFER_SIZE,
|
||||
});
|
||||
cmdbuf.PipelineBarrier(
|
||||
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0,
|
||||
VkMemoryBarrier{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = 0,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
});
|
||||
static constexpr VkMemoryBarrier write_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||
};
|
||||
const VkBufferCopy copy{
|
||||
.srcOffset = offset,
|
||||
.dstOffset = 0,
|
||||
.size = TOTAL_BUFFER_SIZE,
|
||||
};
|
||||
cmdbuf.CopyBuffer(src, dst, copy);
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
0, write_barrier);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -411,7 +411,7 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
|
||||
const VkImageMemoryBarrier image_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
|
||||
.srcAccessMask = is_initialized ? VK_ACCESS_SHADER_WRITE_BIT : VkAccessFlags{},
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
||||
.oldLayout = is_initialized ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
@@ -426,7 +426,8 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(is_initialized ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT : 0,
|
||||
cmdbuf.PipelineBarrier(is_initialized ? VK_PIPELINE_STAGE_ALL_COMMANDS_BIT
|
||||
: VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, image_barrier);
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vk_pipeline);
|
||||
});
|
||||
|
||||
@@ -608,7 +608,7 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
|
||||
const VkImageAspectFlags aspect_mask = ImageAspectMask(src.format);
|
||||
const bool is_dst_msaa = dst.Samples() != VK_SAMPLE_COUNT_1_BIT;
|
||||
const bool is_src_msaa = src.Samples() != VK_SAMPLE_COUNT_1_BIT;
|
||||
if (aspect_mask != ImageAspectMask(dst.format) {
|
||||
if (aspect_mask != ImageAspectMask(dst.format)) {
|
||||
UNIMPLEMENTED_MSG("Incompatible blit from format {} to {}", src.format, dst.format);
|
||||
return;
|
||||
}
|
||||
@@ -914,6 +914,7 @@ void Image::UploadMemory(const StagingBufferRef& map,
|
||||
|
||||
void Image::DownloadMemory(const StagingBufferRef& map, std::span<const BufferImageCopy> copies) {
|
||||
std::vector vk_copies = TransformBufferImageCopies(copies, map.offset, aspect_mask);
|
||||
scheduler->RequestOutsideRenderPassOperationContext();
|
||||
scheduler->Record([buffer = map.buffer, image = *image, aspect_mask = aspect_mask,
|
||||
vk_copies](vk::CommandBuffer cmdbuf) {
|
||||
const VkImageMemoryBarrier read_barrier{
|
||||
|
||||
@@ -599,6 +599,12 @@ void TextureCache<P>::UpdateRenderTargets(bool is_clear) {
|
||||
using namespace VideoCommon::Dirty;
|
||||
auto& flags = maxwell3d.dirty.flags;
|
||||
if (!flags[Dirty::RenderTargets]) {
|
||||
for (size_t index = 0; index < NUM_RT; ++index) {
|
||||
ImageViewId& color_buffer_id = render_targets.color_buffer_ids[index];
|
||||
PrepareImageView(color_buffer_id, true, is_clear && IsFullClear(color_buffer_id));
|
||||
}
|
||||
const ImageViewId depth_buffer_id = render_targets.depth_buffer_id;
|
||||
PrepareImageView(depth_buffer_id, true, is_clear && IsFullClear(depth_buffer_id));
|
||||
return;
|
||||
}
|
||||
flags[Dirty::RenderTargets] = false;
|
||||
|
||||
@@ -169,23 +169,6 @@ template <u32 GOB_EXTENT>
|
||||
return Common::DivCeil(AdjustMipSize(size, level), block_size);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::pair<int, int> Samples(int num_samples) {
|
||||
switch (num_samples) {
|
||||
case 1:
|
||||
return {1, 1};
|
||||
case 2:
|
||||
return {2, 1};
|
||||
case 4:
|
||||
return {2, 2};
|
||||
case 8:
|
||||
return {4, 2};
|
||||
case 16:
|
||||
return {4, 4};
|
||||
}
|
||||
UNREACHABLE_MSG("Invalid number of samples={}", num_samples);
|
||||
return {1, 1};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr Extent2D DefaultBlockSize(PixelFormat format) {
|
||||
return {DefaultBlockWidth(format), DefaultBlockHeight(format)};
|
||||
}
|
||||
@@ -283,14 +266,13 @@ template <u32 GOB_EXTENT>
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr LevelInfo MakeLevelInfo(PixelFormat format, Extent3D size, Extent3D block,
|
||||
u32 num_samples, u32 tile_width_spacing) {
|
||||
const auto [samples_x, samples_y] = Samples(num_samples);
|
||||
u32 tile_width_spacing) {
|
||||
const u32 bytes_per_block = BytesPerBlock(format);
|
||||
return {
|
||||
.size =
|
||||
{
|
||||
.width = size.width * samples_x,
|
||||
.height = size.height * samples_y,
|
||||
.width = size.width,
|
||||
.height = size.height,
|
||||
.depth = size.depth,
|
||||
},
|
||||
.block = block,
|
||||
@@ -301,14 +283,12 @@ template <u32 GOB_EXTENT>
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr LevelInfo MakeLevelInfo(const ImageInfo& info) {
|
||||
return MakeLevelInfo(info.format, info.size, info.block, info.num_samples,
|
||||
info.tile_width_spacing);
|
||||
return MakeLevelInfo(info.format, info.size, info.block, info.tile_width_spacing);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u32 CalculateLevelOffset(PixelFormat format, Extent3D size, Extent3D block,
|
||||
u32 num_samples, u32 tile_width_spacing,
|
||||
u32 level) {
|
||||
const LevelInfo info = MakeLevelInfo(format, size, block, num_samples, tile_width_spacing);
|
||||
u32 tile_width_spacing, u32 level) {
|
||||
const LevelInfo info = MakeLevelInfo(format, size, block, tile_width_spacing);
|
||||
u32 offset = 0;
|
||||
for (u32 current_level = 0; current_level < level; ++current_level) {
|
||||
offset += CalculateLevelSize(info, current_level);
|
||||
@@ -645,8 +625,8 @@ u32 CalculateLayerStride(const ImageInfo& info) noexcept {
|
||||
|
||||
u32 CalculateLayerSize(const ImageInfo& info) noexcept {
|
||||
ASSERT(info.type != ImageType::Linear);
|
||||
return CalculateLevelOffset(info.format, info.size, info.block, info.num_samples,
|
||||
info.tile_width_spacing, info.resources.levels);
|
||||
return CalculateLevelOffset(info.format, info.size, info.block, info.tile_width_spacing,
|
||||
info.resources.levels);
|
||||
}
|
||||
|
||||
LevelArray CalculateMipLevelOffsets(const ImageInfo& info) noexcept {
|
||||
@@ -1195,37 +1175,37 @@ static_assert(CalculateLevelSize(LevelInfo{{1920, 1080, 1}, {0, 2, 0}, {1, 1}, 2
|
||||
0x7f8000);
|
||||
static_assert(CalculateLevelSize(LevelInfo{{32, 32, 1}, {0, 0, 4}, {1, 1}, 4, 0}, 0) == 0x4000);
|
||||
|
||||
static_assert(CalculateLevelOffset(PixelFormat::R8_SINT, {1920, 1080, 1}, {0, 2, 0}, 1, 0, 7) ==
|
||||
static_assert(CalculateLevelOffset(PixelFormat::R8_SINT, {1920, 1080, 1}, {0, 2, 0}, 0, 7) ==
|
||||
0x2afc00);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::ASTC_2D_12X12_UNORM, {8192, 4096, 1}, {0, 2, 0}, 1,
|
||||
0, 12) == 0x50d200);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::ASTC_2D_12X12_UNORM, {8192, 4096, 1}, {0, 2, 0}, 0,
|
||||
12) == 0x50d200);
|
||||
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
|
||||
0) == 0);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
|
||||
1) == 0x400000);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
|
||||
2) == 0x500000);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
|
||||
3) == 0x540000);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
|
||||
4) == 0x550000);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
|
||||
5) == 0x554000);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
|
||||
6) == 0x555000);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
|
||||
7) == 0x555400);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
|
||||
8) == 0x555600);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
|
||||
9) == 0x555800);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 0) ==
|
||||
0);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 1) ==
|
||||
0x400000);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 2) ==
|
||||
0x500000);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 3) ==
|
||||
0x540000);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 4) ==
|
||||
0x550000);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 5) ==
|
||||
0x554000);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 6) ==
|
||||
0x555000);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 7) ==
|
||||
0x555400);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 8) ==
|
||||
0x555600);
|
||||
static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 9) ==
|
||||
0x555800);
|
||||
|
||||
constexpr u32 ValidateLayerSize(PixelFormat format, u32 width, u32 height, u32 block_height,
|
||||
u32 tile_width_spacing, u32 level) {
|
||||
const Extent3D size{width, height, 1};
|
||||
const Extent3D block{0, block_height, 0};
|
||||
const u32 offset = CalculateLevelOffset(format, size, block, 1, tile_width_spacing, level);
|
||||
const u32 offset = CalculateLevelOffset(format, size, block, tile_width_spacing, level);
|
||||
return AlignLayerSize(offset, size, block, DefaultBlockHeight(format), tile_width_spacing);
|
||||
}
|
||||
|
||||
|
||||
@@ -404,9 +404,11 @@ void GameList::ValidateEntry(const QModelIndex& item) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto title_id = selected.data(GameListItemPath::ProgramIdRole).toULongLong();
|
||||
|
||||
// Users usually want to run a different game after closing one
|
||||
search_field->clear();
|
||||
emit GameChosen(file_path);
|
||||
emit GameChosen(file_path, title_id);
|
||||
break;
|
||||
}
|
||||
case GameListItemType::AddDir:
|
||||
@@ -548,10 +550,10 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
|
||||
emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path);
|
||||
});
|
||||
connect(start_game, &QAction::triggered, [this, path]() {
|
||||
emit BootGame(QString::fromStdString(path), 0, StartGameType::Normal);
|
||||
emit BootGame(QString::fromStdString(path), 0, 0, StartGameType::Normal);
|
||||
});
|
||||
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]() {
|
||||
emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path);
|
||||
|
||||
@@ -88,8 +88,9 @@ public:
|
||||
static const QStringList supported_file_extensions;
|
||||
|
||||
signals:
|
||||
void BootGame(const QString& game_path, std::size_t program_index, StartGameType type);
|
||||
void GameChosen(const QString& game_path);
|
||||
void BootGame(const QString& game_path, u64 program_id, std::size_t program_index,
|
||||
StartGameType type);
|
||||
void GameChosen(const QString& game_path, const u64 title_id = 0);
|
||||
void ShouldCancelWorker();
|
||||
void OpenFolderRequested(u64 program_id, GameListOpenTarget target,
|
||||
const std::string& game_path);
|
||||
|
||||
@@ -336,18 +336,44 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::vector<u8> icon;
|
||||
[[maybe_unused]] const auto res1 = loader->ReadIcon(icon);
|
||||
std::vector<u64> program_ids;
|
||||
loader->ReadProgramIds(program_ids);
|
||||
|
||||
std::string name = " ";
|
||||
[[maybe_unused]] const auto res3 = loader->ReadTitle(name);
|
||||
if (res2 == Loader::ResultStatus::Success && program_ids.size() > 1 &&
|
||||
(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(),
|
||||
system.GetContentProvider()};
|
||||
std::vector<u8> icon;
|
||||
[[maybe_unused]] const auto res1 = loader->ReadIcon(icon);
|
||||
|
||||
emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, program_id,
|
||||
compatibility_list, patch),
|
||||
parent_dir);
|
||||
std::string name = " ";
|
||||
[[maybe_unused]] const auto res3 = loader->ReadTitle(name);
|
||||
|
||||
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) {
|
||||
watch_list.append(QString::fromStdString(physical_name));
|
||||
|
||||
@@ -1221,7 +1221,7 @@ void GMainWindow::AllowOSSleep() {
|
||||
#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...
|
||||
if (emu_thread != nullptr)
|
||||
ShutdownGame();
|
||||
@@ -1244,7 +1244,7 @@ bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) {
|
||||
});
|
||||
|
||||
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() &
|
||||
static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0;
|
||||
@@ -1331,7 +1331,8 @@ void GMainWindow::SelectAndSetCurrentUser() {
|
||||
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...");
|
||||
StoreRecentFile(filename); // Put the filename on top of the list
|
||||
|
||||
@@ -1341,7 +1342,7 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index, S
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
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 &&
|
||||
type == StartGameType::Normal) {
|
||||
@@ -1369,7 +1370,7 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index, S
|
||||
SelectAndSetCurrentUser();
|
||||
}
|
||||
|
||||
if (!LoadROM(filename, program_index))
|
||||
if (!LoadROM(filename, program_id, program_index))
|
||||
return;
|
||||
|
||||
// Create and start the emulation thread
|
||||
@@ -1548,8 +1549,8 @@ void GMainWindow::UpdateRecentFiles() {
|
||||
ui.menu_recent_files->setEnabled(num_recent_files != 0);
|
||||
}
|
||||
|
||||
void GMainWindow::OnGameListLoadFile(QString game_path) {
|
||||
BootGame(game_path);
|
||||
void GMainWindow::OnGameListLoadFile(QString game_path, u64 program_id) {
|
||||
BootGame(game_path, program_id);
|
||||
}
|
||||
|
||||
void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target,
|
||||
@@ -2450,7 +2451,7 @@ void GMainWindow::OnLoadComplete() {
|
||||
|
||||
void GMainWindow::OnExecuteProgram(std::size_t program_index) {
|
||||
ShutdownGame();
|
||||
BootGame(last_filename_booted, program_index);
|
||||
BootGame(last_filename_booted, 0, program_index);
|
||||
}
|
||||
|
||||
void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) {
|
||||
|
||||
@@ -186,8 +186,8 @@ private:
|
||||
void PreventOSSleep();
|
||||
void AllowOSSleep();
|
||||
|
||||
bool LoadROM(const QString& filename, std::size_t program_index);
|
||||
void BootGame(const QString& filename, std::size_t program_index = 0,
|
||||
bool LoadROM(const QString& filename, u64 program_id, std::size_t program_index);
|
||||
void BootGame(const QString& filename, u64 program_id = 0, std::size_t program_index = 0,
|
||||
StartGameType with_config = StartGameType::Normal);
|
||||
void ShutdownGame();
|
||||
|
||||
@@ -238,7 +238,7 @@ private slots:
|
||||
void OnOpenQuickstartGuide();
|
||||
void OnOpenFAQ();
|
||||
/// 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,
|
||||
const std::string& game_path);
|
||||
void OnTransferableShaderCacheOpenFile(u64 program_id);
|
||||
|
||||
@@ -38,6 +38,11 @@ target_include_directories(yuzu-cmd PRIVATE ${RESOURCES_DIR})
|
||||
|
||||
target_include_directories(yuzu-cmd PRIVATE ../../externals/Vulkan-Headers/include)
|
||||
|
||||
if (YUZU_USE_EXTERNAL_SDL2)
|
||||
target_compile_definitions(yuzu-cmd PRIVATE -DYUZU_USE_EXTERNAL_SDL2)
|
||||
target_include_directories(yuzu-cmd PRIVATE ${PROJECT_BINARY_DIR}/externals/SDL/include)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
install(TARGETS yuzu-cmd RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
|
||||
endif()
|
||||
|
||||
@@ -292,6 +292,8 @@ void Config::ReadValues() {
|
||||
|
||||
ReadSetting("ControlsGeneral", Settings::values.motion_device);
|
||||
|
||||
ReadSetting("ControlsGeneral", Settings::values.touch_device);
|
||||
|
||||
ReadSetting("ControlsGeneral", Settings::values.keyboard_enabled);
|
||||
|
||||
ReadSetting("ControlsGeneral", Settings::values.debug_pad_enabled);
|
||||
@@ -414,11 +416,31 @@ void Config::ReadValues() {
|
||||
}
|
||||
|
||||
ReadSetting("System", Settings::values.language_index);
|
||||
ReadSetting("System", Settings::values.region_index);
|
||||
ReadSetting("System", Settings::values.time_zone_index);
|
||||
ReadSetting("System", Settings::values.sound_index);
|
||||
|
||||
// Core
|
||||
ReadSetting("Core", Settings::values.use_multi_core);
|
||||
|
||||
// Cpu
|
||||
ReadSetting("Cpu", Settings::values.cpu_accuracy);
|
||||
ReadSetting("Cpu", Settings::values.cpu_debug_mode);
|
||||
ReadSetting("Cpu", Settings::values.cpuopt_page_tables);
|
||||
ReadSetting("Cpu", Settings::values.cpuopt_block_linking);
|
||||
ReadSetting("Cpu", Settings::values.cpuopt_return_stack_buffer);
|
||||
ReadSetting("Cpu", Settings::values.cpuopt_fast_dispatcher);
|
||||
ReadSetting("Cpu", Settings::values.cpuopt_context_elimination);
|
||||
ReadSetting("Cpu", Settings::values.cpuopt_const_prop);
|
||||
ReadSetting("Cpu", Settings::values.cpuopt_misc_ir);
|
||||
ReadSetting("Cpu", Settings::values.cpuopt_reduce_misalign_checks);
|
||||
ReadSetting("Cpu", Settings::values.cpuopt_fastmem);
|
||||
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_unfuse_fma);
|
||||
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_reduce_fp_error);
|
||||
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
|
||||
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_inaccurate_nan);
|
||||
ReadSetting("Cpu", Settings::values.cpuopt_unsafe_fastmem_check);
|
||||
|
||||
// Renderer
|
||||
ReadSetting("Renderer", Settings::values.renderer_backend);
|
||||
ReadSetting("Renderer", Settings::values.renderer_debug);
|
||||
@@ -438,6 +460,7 @@ void Config::ReadValues() {
|
||||
ReadSetting("Renderer", Settings::values.use_nvdec_emulation);
|
||||
ReadSetting("Renderer", Settings::values.accelerate_astc);
|
||||
ReadSetting("Renderer", Settings::values.use_fast_gpu_time);
|
||||
ReadSetting("Renderer", Settings::values.use_caches_gc);
|
||||
|
||||
ReadSetting("Renderer", Settings::values.bg_red);
|
||||
ReadSetting("Renderer", Settings::values.bg_green);
|
||||
@@ -458,7 +481,6 @@ void Config::ReadValues() {
|
||||
// Debugging
|
||||
Settings::values.record_frame_times =
|
||||
sdl2_config->GetBoolean("Debugging", "record_frame_times", false);
|
||||
ReadSetting("Debugging", Settings::values.program_args);
|
||||
ReadSetting("Debugging", Settings::values.dump_exefs);
|
||||
ReadSetting("Debugging", Settings::values.dump_nso);
|
||||
ReadSetting("Debugging", Settings::values.enable_fs_access_log);
|
||||
|
||||
@@ -65,6 +65,13 @@ button_screenshot=
|
||||
lstick=
|
||||
rstick=
|
||||
|
||||
# To use the debug_pad, prepend `debug_pad_` before each button setting above.
|
||||
# i.e. debug_pad_button_a=
|
||||
|
||||
# Enable debug pad inputs to the guest
|
||||
# 0 (default): Disabled, 1: Enabled
|
||||
debug_pad_enabled =
|
||||
|
||||
# Whether to enable or disable vibration
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
vibration_enabled=
|
||||
@@ -73,6 +80,10 @@ vibration_enabled=
|
||||
# 0 (default): Disabled, 1: Enabled
|
||||
enable_accurate_vibrations=
|
||||
|
||||
# Enables controller motion inputs
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
motion_enabled =
|
||||
|
||||
# for motion input, the following devices are available:
|
||||
# - "motion_emu" (default) for emulating motion input from mouse input. Required parameters:
|
||||
# - "update_period": update period in milliseconds (default to 100)
|
||||
@@ -98,19 +109,30 @@ use_touch_from_button=
|
||||
#touch_from_button_maps_0_bind_1=bar
|
||||
# etc.
|
||||
|
||||
# Most desktop operating systems do not expose a way to poll the motion state of the controllers
|
||||
# so as a way around it, cemuhook created a udp client/server protocol to broadcast the data directly
|
||||
# from a controller device to the client program. Citra has a client that can connect and read
|
||||
# from any cemuhook compatible motion program.
|
||||
# List of Cemuhook UDP servers, delimited by ','.
|
||||
# Default: 127.0.0.1:26760
|
||||
# Example: 127.0.0.1:26760,123.4.5.67:26761
|
||||
udp_input_servers =
|
||||
|
||||
# IPv4 address of the udp input server (Default "127.0.0.1")
|
||||
udp_input_address=127.0.0.1
|
||||
# Enable controlling an axis via a mouse input.
|
||||
# 0 (default): Off, 1: On
|
||||
mouse_panning =
|
||||
|
||||
# Port of the udp input server. (Default 26760)
|
||||
udp_input_port=
|
||||
# Set mouse sensitivity.
|
||||
# Default: 1.0
|
||||
mouse_panning_sensitivity =
|
||||
|
||||
# The pad to request data on. Should be between 0 (Pad 1) and 3 (Pad 4). (Default 0)
|
||||
udp_pad_index=
|
||||
# Emulate an analog control stick from keyboard inputs.
|
||||
# 0 (default): Disabled, 1: Enabled
|
||||
emulate_analog_keyboard =
|
||||
|
||||
# Enable mouse inputs to the guest
|
||||
# 0 (default): Disabled, 1: Enabled
|
||||
mouse_enabled =
|
||||
|
||||
# Enable keyboard inputs to the guest
|
||||
# 0 (default): Disabled, 1: Enabled
|
||||
keyboard_enabled =
|
||||
|
||||
[Core]
|
||||
# Whether to use multi-core for CPU emulation
|
||||
@@ -118,6 +140,17 @@ udp_pad_index=
|
||||
use_multi_core=
|
||||
|
||||
[Cpu]
|
||||
# Adjusts various optimizations.
|
||||
# Auto-select mode enables choice unsafe optimizations.
|
||||
# Accurate enables only safe optimizations.
|
||||
# Unsafe allows any unsafe optimizations.
|
||||
# 0 (default): Auto-select, 1: Accurate, 2: Enable unsafe optimizations
|
||||
cpu_accuracy =
|
||||
|
||||
# Allow disabling safe optimizations.
|
||||
# 0 (default): Disabled, 1: Enabled
|
||||
cpu_debug_mode =
|
||||
|
||||
# Enable inline page tables optimization (faster guest memory access)
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_page_tables =
|
||||
@@ -154,6 +187,31 @@ cpuopt_reduce_misalign_checks =
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_fastmem =
|
||||
|
||||
# Enable unfuse FMA (improve performance on CPUs without FMA)
|
||||
# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_unsafe_unfuse_fma =
|
||||
|
||||
# Enable faster FRSQRTE and FRECPE
|
||||
# Only enabled if cpu_accuracy is set to Unsafe.
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_unsafe_reduce_fp_error =
|
||||
|
||||
# Enable faster ASIMD instructions (32 bits only)
|
||||
# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_unsafe_ignore_standard_fpcr =
|
||||
|
||||
# Enable inaccurate NaN handling
|
||||
# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_unsafe_inaccurate_nan =
|
||||
|
||||
# Disable address space checks (64 bits only)
|
||||
# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
cpuopt_unsafe_fastmem_check =
|
||||
|
||||
[Renderer]
|
||||
# Which backend API to use.
|
||||
# 0 (default): OpenGL, 1: Vulkan
|
||||
@@ -166,14 +224,6 @@ debug =
|
||||
# Which Vulkan physical device to use (defaults to 0)
|
||||
vulkan_device =
|
||||
|
||||
# Whether to use software or hardware rendering.
|
||||
# 0: Software, 1 (default): Hardware
|
||||
use_hw_renderer =
|
||||
|
||||
# Whether to use the Just-In-Time (JIT) compiler for shader emulation
|
||||
# 0: Interpreter (slow), 1 (default): JIT (fast)
|
||||
use_shader_jit =
|
||||
|
||||
# Aspect ratio
|
||||
# 0: Default (16:9), 1: Force 4:3, 2: Force 21:9, 3: Stretch to Window
|
||||
aspect_ratio =
|
||||
@@ -211,21 +261,20 @@ use_frame_limit =
|
||||
frame_limit =
|
||||
|
||||
# Whether to use disk based shader cache
|
||||
# 0 (default): Off, 1 : On
|
||||
# 0: Off, 1 (default): On
|
||||
use_disk_shader_cache =
|
||||
|
||||
# Which gpu accuracy level to use
|
||||
# 0 (Normal), 1 (High), 2 (Extreme)
|
||||
# 0: Normal, 1 (default): High, 2: Extreme (Very slow)
|
||||
gpu_accuracy =
|
||||
|
||||
# Whether to use asynchronous GPU emulation
|
||||
# 0 : Off (slow), 1 (default): On (fast)
|
||||
use_asynchronous_gpu_emulation =
|
||||
|
||||
# Forces VSync on the display thread. Usually doesn't impact performance, but on some drivers it can
|
||||
# so only turn this off if you notice a speed difference.
|
||||
# Inform the guest that GPU operations completed more quickly than they did.
|
||||
# 0: Off, 1 (default): On
|
||||
use_vsync =
|
||||
use_fast_gpu_time =
|
||||
|
||||
# Whether to use garbage collection or not for GPU caches.
|
||||
# 0 (default): Off, 1: On
|
||||
@@ -237,31 +286,6 @@ bg_red =
|
||||
bg_blue =
|
||||
bg_green =
|
||||
|
||||
[Layout]
|
||||
# Layout for the screen inside the render window.
|
||||
# 0 (default): Default Top Bottom Screen, 1: Single Screen Only, 2: Large Screen Small Screen
|
||||
layout_option =
|
||||
|
||||
# Toggle custom layout (using the settings below) on or off.
|
||||
# 0 (default): Off, 1: On
|
||||
custom_layout =
|
||||
|
||||
# Screen placement when using Custom layout option
|
||||
# 0x, 0y is the top left corner of the render window.
|
||||
custom_top_left =
|
||||
custom_top_top =
|
||||
custom_top_right =
|
||||
custom_top_bottom =
|
||||
custom_bottom_left =
|
||||
custom_bottom_top =
|
||||
custom_bottom_right =
|
||||
custom_bottom_bottom =
|
||||
|
||||
# Swaps the prominent screen with the other screen.
|
||||
# For example, if Single Screen is chosen, setting this to 1 will display the bottom screen instead of the top screen.
|
||||
# 0 (default): Top Screen is prominent, 1: Bottom Screen is prominent
|
||||
swap_screen =
|
||||
|
||||
[Audio]
|
||||
# Which audio output engine to use.
|
||||
# auto (default): Auto-select
|
||||
@@ -308,10 +332,6 @@ gamecard_path =
|
||||
# 1 (default): Yes, 0: No
|
||||
use_docked_mode =
|
||||
|
||||
# Allow the use of NFC in games
|
||||
# 1 (default): Yes, 0 : No
|
||||
enable_nfc =
|
||||
|
||||
# Sets the seed for the RNG generator built into the switch
|
||||
# rng_seed will be ignored and randomly generated if rng_seed_enabled is false
|
||||
rng_seed_enabled =
|
||||
@@ -323,10 +343,6 @@ rng_seed =
|
||||
custom_rtc_enabled =
|
||||
custom_rtc =
|
||||
|
||||
# Sets the account username, max length is 32 characters
|
||||
# yuzu (default)
|
||||
username = yuzu
|
||||
|
||||
# Sets the systems language index
|
||||
# 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese,
|
||||
# 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French,
|
||||
@@ -335,17 +351,25 @@ language_index =
|
||||
|
||||
# The system region that yuzu will use during emulation
|
||||
# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan
|
||||
region_value =
|
||||
region_index =
|
||||
|
||||
# The system time zone that yuzu will use during emulation
|
||||
# 0: Auto-select (default), 1: Default (system archive value), Others: Index for specified time zone
|
||||
time_zone_index =
|
||||
|
||||
# Sets the sound output mode.
|
||||
# 0: Mono, 1 (default): Stereo, 2: Surround
|
||||
sound_index =
|
||||
|
||||
[Miscellaneous]
|
||||
# A filter which removes logs below a certain logging level.
|
||||
# Examples: *:Debug Kernel.SVC:Trace Service.*:Critical
|
||||
log_filter = *:Trace
|
||||
|
||||
# Use developer keys
|
||||
# 0 (default): Disabled, 1: Enabled
|
||||
use_dev_keys =
|
||||
|
||||
[Debugging]
|
||||
# Record frame time data, can be found in the log directory. Boolean value
|
||||
record_frame_times =
|
||||
@@ -355,6 +379,8 @@ dump_exefs=false
|
||||
dump_nso=false
|
||||
# Determines whether or not yuzu will save the filesystem access log.
|
||||
enable_fs_access_log=false
|
||||
# Enables verbose reporting services
|
||||
reporting_services =
|
||||
# Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode
|
||||
# false: Retail/Normal Mode (default), true: Kiosk Mode
|
||||
quest_flag =
|
||||
@@ -393,4 +419,4 @@ title_ids =
|
||||
# For each title ID, have a key/value pair called `disabled_<title_id>` equal to the names of the add-ons to disable (sep. by '|')
|
||||
# e.x. disabled_0100000000010000 = Update|DLC <- disables Updates and DLC on Super Mario Odyssey
|
||||
)";
|
||||
}
|
||||
} // namespace DefaultINI
|
||||
|
||||
@@ -2,15 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// Ignore -Wimplicit-fallthrough due to https://github.com/libsdl-org/SDL/issues/4307
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#endif
|
||||
#include <SDL.h>
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/scm_rev.h"
|
||||
@@ -130,12 +122,6 @@ void EmuWindow_SDL2::OnResize() {
|
||||
}
|
||||
|
||||
void EmuWindow_SDL2::Fullscreen() {
|
||||
if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_ERROR(Frontend, "Fullscreening failed: {}", SDL_GetError());
|
||||
|
||||
// Try a different fullscreening method
|
||||
LOG_INFO(Frontend, "Attempting to use borderless fullscreen...");
|
||||
if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) {
|
||||
@@ -144,6 +130,12 @@ void EmuWindow_SDL2::Fullscreen() {
|
||||
|
||||
LOG_ERROR(Frontend, "Borderless fullscreening failed: {}", SDL_GetError());
|
||||
|
||||
if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_ERROR(Frontend, "Fullscreening failed: {}", SDL_GetError());
|
||||
|
||||
// Fallback algorithm: Maximise window.
|
||||
// Works on all systems (unless something is seriously wrong), so no fallback for this one.
|
||||
LOG_INFO(Frontend, "Falling back on a maximised window...");
|
||||
|
||||
@@ -7,15 +7,7 @@
|
||||
#include <string>
|
||||
|
||||
#define SDL_MAIN_HANDLED
|
||||
// Ignore -Wimplicit-fallthrough due to https://github.com/libsdl-org/SDL/issues/4307
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#endif
|
||||
#include <SDL.h>
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <glad/glad.h>
|
||||
|
||||
@@ -15,19 +15,16 @@
|
||||
#include "video_core/renderer_vulkan/renderer_vulkan.h"
|
||||
#include "yuzu_cmd/emu_window/emu_window_sdl2_vk.h"
|
||||
|
||||
// Include these late to avoid polluting everything with Xlib macros
|
||||
// Ignore -Wimplicit-fallthrough due to https://github.com/libsdl-org/SDL/issues/4307
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#ifdef YUZU_USE_EXTERNAL_SDL2
|
||||
// Include this before SDL.h to prevent the external from including a dummy
|
||||
#define USING_GENERATED_CONFIG_H
|
||||
#include <SDL_config.h>
|
||||
#endif
|
||||
|
||||
#include <SDL.h>
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
#include <SDL_syswm.h>
|
||||
|
||||
EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem)
|
||||
EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem, bool fullscreen)
|
||||
: EmuWindow_SDL2{input_subsystem} {
|
||||
const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name,
|
||||
Common::g_scm_branch, Common::g_scm_desc);
|
||||
@@ -45,12 +42,21 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste
|
||||
|
||||
SetWindowIcon();
|
||||
|
||||
if (fullscreen) {
|
||||
Fullscreen();
|
||||
}
|
||||
|
||||
switch (wm.subsystem) {
|
||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||
case SDL_SYSWM_TYPE::SDL_SYSWM_WINDOWS:
|
||||
window_info.type = Core::Frontend::WindowSystemType::Windows;
|
||||
window_info.render_surface = reinterpret_cast<void*>(wm.info.win.window);
|
||||
break;
|
||||
#else
|
||||
case SDL_SYSWM_TYPE::SDL_SYSWM_WINDOWS:
|
||||
LOG_CRITICAL(Frontend, "Window manager subsystem Windows not compiled");
|
||||
std::exit(EXIT_FAILURE);
|
||||
break;
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_X11
|
||||
case SDL_SYSWM_TYPE::SDL_SYSWM_X11:
|
||||
@@ -58,6 +64,11 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste
|
||||
window_info.display_connection = wm.info.x11.display;
|
||||
window_info.render_surface = reinterpret_cast<void*>(wm.info.x11.window);
|
||||
break;
|
||||
#else
|
||||
case SDL_SYSWM_TYPE::SDL_SYSWM_X11:
|
||||
LOG_CRITICAL(Frontend, "Window manager subsystem X11 not compiled");
|
||||
std::exit(EXIT_FAILURE);
|
||||
break;
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND
|
||||
case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND:
|
||||
@@ -65,6 +76,11 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste
|
||||
window_info.display_connection = wm.info.wl.display;
|
||||
window_info.render_surface = wm.info.wl.surface;
|
||||
break;
|
||||
#else
|
||||
case SDL_SYSWM_TYPE::SDL_SYSWM_WAYLAND:
|
||||
LOG_CRITICAL(Frontend, "Window manager subsystem Wayland not compiled");
|
||||
std::exit(EXIT_FAILURE);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
LOG_CRITICAL(Frontend, "Window manager subsystem not implemented");
|
||||
|
||||
@@ -19,7 +19,7 @@ class InputSubsystem;
|
||||
|
||||
class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 {
|
||||
public:
|
||||
explicit EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem);
|
||||
explicit EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem, bool fullscreen);
|
||||
~EmuWindow_SDL2_VK() override;
|
||||
|
||||
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override;
|
||||
|
||||
@@ -175,7 +175,7 @@ int main(int argc, char** argv) {
|
||||
emu_window = std::make_unique<EmuWindow_SDL2_GL>(&input_subsystem, fullscreen);
|
||||
break;
|
||||
case Settings::RendererBackend::Vulkan:
|
||||
emu_window = std::make_unique<EmuWindow_SDL2_VK>(&input_subsystem);
|
||||
emu_window = std::make_unique<EmuWindow_SDL2_VK>(&input_subsystem, fullscreen);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user