diff options
96 files changed, 2926 insertions, 1825 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c0e49c03..ce46a2c2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,8 +118,17 @@ message(STATUS "Target architecture: ${ARCHITECTURE}") # Configure C++ standard # =========================== -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) +# boost asio's concept usage doesn't play nicely with some compilers yet. +add_definitions(-DBOOST_ASIO_DISABLE_CONCEPTS) +if (MSVC) + add_compile_options(/std:c++latest) + + # cubeb and boost still make use of deprecated result_of. + add_definitions(-D_HAS_DEPRECATED_RESULT_OF) +else() + set(CMAKE_CXX_STANDARD 20) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif() # Output binaries to bin/ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) @@ -330,14 +339,16 @@ elseif(SDL2_FOUND) endif() # Ensure libusb is properly configured (based on dolphin libusb include) -include(FindPkgConfig) -find_package(LibUSB) +if(NOT APPLE) + include(FindPkgConfig) + find_package(LibUSB) +endif() if (NOT LIBUSB_FOUND) add_subdirectory(externals/libusb) + set(LIBUSB_INCLUDE_DIR "") set(LIBUSB_LIBRARIES usb) endif() - # Prefer the -pthread flag on Linux. set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) @@ -2,7 +2,7 @@ yuzu emulator ============= [![Travis CI Build Status](https://travis-ci.com/yuzu-emu/yuzu.svg?branch=master)](https://travis-ci.com/yuzu-emu/yuzu) [![Azure Mainline CI Build Status](https://dev.azure.com/yuzu-emu/yuzu/_apis/build/status/yuzu%20mainline?branchName=master)](https://dev.azure.com/yuzu-emu/yuzu/) -[![Discord](https://img.shields.io/discord/398318088170242053?color=%237289DA&label=yuzu&logo=discord&logoColor=white)](https://discord.gg/XQV6dn9) +[![Discord](https://img.shields.io/discord/398318088170242053?color=%237289DA&label=yuzu&logo=discord&logoColor=white)](https://discord.com/invite/u77vRWY) yuzu is an experimental open-source emulator for the Nintendo Switch from the creators of [Citra](https://citra-emu.org/). @@ -16,7 +16,7 @@ yuzu is licensed under the GPLv2 (or any later version). Refer to the license.tx Check out our [website](https://yuzu-emu.org/)! -For development discussion, please join us on [Discord](https://discord.gg/XQV6dn9). +For development discussion, please join us on [Discord](https://discord.com/invite/u77vRWY). ### Development diff --git a/externals/dynarmic b/externals/dynarmic -Subproject 4f967387c07365b7ea35d2fa3e19b7df8872a09 +Subproject 82417da7803e2cf18efc28a1cd3f3d0a4b6045a diff --git a/src/common/alignment.h b/src/common/alignment.h index f8c49e079..b37044bb6 100644 --- a/src/common/alignment.h +++ b/src/common/alignment.h @@ -11,7 +11,9 @@ namespace Common { template <typename T> constexpr T AlignUp(T value, std::size_t size) { static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); - return static_cast<T>(value + (size - value % size) % size); + auto mod{static_cast<T>(value % size)}; + value -= mod; + return static_cast<T>(mod == T{0} ? value : value + size); } template <typename T> diff --git a/src/common/swap.h b/src/common/swap.h index 71932c2bb..7665942a2 100644 --- a/src/common/swap.h +++ b/src/common/swap.h @@ -17,43 +17,14 @@ #pragma once -#include <type_traits> - #if defined(_MSC_VER) #include <cstdlib> #endif +#include <bit> #include <cstring> +#include <type_traits> #include "common/common_types.h" -// GCC -#ifdef __GNUC__ - -#if __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) && !defined(COMMON_LITTLE_ENDIAN) -#define COMMON_LITTLE_ENDIAN 1 -#elif __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) && !defined(COMMON_BIG_ENDIAN) -#define COMMON_BIG_ENDIAN 1 -#endif - -// LLVM/clang -#elif defined(__clang__) - -#if __LITTLE_ENDIAN__ && !defined(COMMON_LITTLE_ENDIAN) -#define COMMON_LITTLE_ENDIAN 1 -#elif __BIG_ENDIAN__ && !defined(COMMON_BIG_ENDIAN) -#define COMMON_BIG_ENDIAN 1 -#endif - -// MSVC -#elif defined(_MSC_VER) && !defined(COMMON_BIG_ENDIAN) && !defined(COMMON_LITTLE_ENDIAN) - -#define COMMON_LITTLE_ENDIAN 1 -#endif - -// Worst case, default to little endian. -#if !COMMON_BIG_ENDIAN && !COMMON_LITTLE_ENDIAN -#define COMMON_LITTLE_ENDIAN 1 -#endif - namespace Common { #ifdef _MSC_VER @@ -675,17 +646,8 @@ struct AddEndian<T, SwapTag> { }; // Alias LETag/BETag as KeepTag/SwapTag depending on the system -#if COMMON_LITTLE_ENDIAN - -using LETag = KeepTag; -using BETag = SwapTag; - -#else - -using BETag = KeepTag; -using LETag = SwapTag; - -#endif +using LETag = std::conditional_t<std::endian::native == std::endian::little, KeepTag, SwapTag>; +using BETag = std::conditional_t<std::endian::native == std::endian::big, KeepTag, SwapTag>; // Aliases for LE types using u16_le = AddEndian<u16, LETag>::type; diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 0d4ab95b7..443ca72eb 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -142,10 +142,32 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& // Timing config.wall_clock_cntpct = uses_wall_clock; - // Optimizations - if (Settings::values.disable_cpu_opt) { - config.enable_optimizations = false; - config.enable_fast_dispatch = false; + // Safe optimizations + if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) { + if (!Settings::values.cpuopt_page_tables) { + config.page_table = nullptr; + } + if (!Settings::values.cpuopt_block_linking) { + config.optimizations &= ~Dynarmic::OptimizationFlag::BlockLinking; + } + if (!Settings::values.cpuopt_return_stack_buffer) { + config.optimizations &= ~Dynarmic::OptimizationFlag::ReturnStackBuffer; + } + if (!Settings::values.cpuopt_fast_dispatcher) { + config.optimizations &= ~Dynarmic::OptimizationFlag::FastDispatch; + } + if (!Settings::values.cpuopt_context_elimination) { + config.optimizations &= ~Dynarmic::OptimizationFlag::GetSetElimination; + } + if (!Settings::values.cpuopt_const_prop) { + config.optimizations &= ~Dynarmic::OptimizationFlag::ConstProp; + } + if (!Settings::values.cpuopt_misc_ir) { + config.optimizations &= ~Dynarmic::OptimizationFlag::MiscIROpt; + } + if (!Settings::values.cpuopt_reduce_misalign_checks) { + config.only_detect_misalignment_via_page_table_on_page_boundary = false; + } } return std::make_unique<Dynarmic::A32::Jit>(config); diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 790981034..a63a04a25 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -191,15 +191,37 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable& // Unpredictable instructions config.define_unpredictable_behaviour = true; - // Optimizations - if (Settings::values.disable_cpu_opt) { - config.enable_optimizations = false; - config.enable_fast_dispatch = false; - } - // Timing config.wall_clock_cntpct = uses_wall_clock; + // Safe optimizations + if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) { + if (!Settings::values.cpuopt_page_tables) { + config.page_table = nullptr; + } + if (!Settings::values.cpuopt_block_linking) { + config.optimizations &= ~Dynarmic::OptimizationFlag::BlockLinking; + } + if (!Settings::values.cpuopt_return_stack_buffer) { + config.optimizations &= ~Dynarmic::OptimizationFlag::ReturnStackBuffer; + } + if (!Settings::values.cpuopt_fast_dispatcher) { + config.optimizations &= ~Dynarmic::OptimizationFlag::FastDispatch; + } + if (!Settings::values.cpuopt_context_elimination) { + config.optimizations &= ~Dynarmic::OptimizationFlag::GetSetElimination; + } + if (!Settings::values.cpuopt_const_prop) { + config.optimizations &= ~Dynarmic::OptimizationFlag::ConstProp; + } + if (!Settings::values.cpuopt_misc_ir) { + config.optimizations &= ~Dynarmic::OptimizationFlag::MiscIROpt; + } + if (!Settings::values.cpuopt_reduce_misalign_checks) { + config.only_detect_misalignment_via_page_table_on_page_boundary = false; + } + } + return std::make_shared<Dynarmic::A64::Jit>(config); } diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index 35929ed94..17420c941 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h @@ -9,6 +9,9 @@ #include <functional> #include <memory> #include <thread> + +#include "common/fiber.h" +#include "common/thread.h" #include "core/hardware_properties.h" namespace Common { @@ -46,9 +49,9 @@ public: void Pause(bool paused); - std::function<void(void*)> GetGuestThreadStartFunc(); - std::function<void(void*)> GetIdleThreadStartFunc(); - std::function<void(void*)> GetSuspendThreadStartFunc(); + static std::function<void(void*)> GetGuestThreadStartFunc(); + static std::function<void(void*)> GetIdleThreadStartFunc(); + static std::function<void(void*)> GetSuspendThreadStartFunc(); void* GetStartFuncParamater(); void PreemptSingleCore(bool from_running_enviroment = true); @@ -97,7 +100,6 @@ private: bool is_async_gpu{}; bool is_multicore{}; std::atomic<std::size_t> current_core{}; - std::size_t preemption_count{}; std::size_t idle_count{}; static constexpr std::size_t max_cycle_runs = 5; diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp index 8935a62c3..285277ef8 100644 --- a/src/core/file_sys/bis_factory.cpp +++ b/src/core/file_sys/bis_factory.cpp @@ -12,6 +12,10 @@ namespace FileSys { +constexpr u64 NAND_USER_SIZE = 0x680000000; // 26624 MiB +constexpr u64 NAND_SYSTEM_SIZE = 0xA0000000; // 2560 MiB +constexpr u64 NAND_TOTAL_SIZE = 0x747C00000; // 29820 MiB + BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir dump_root_) : nand_root(std::move(nand_root_)), load_root(std::move(load_root_)), dump_root(std::move(dump_root_)), @@ -110,30 +114,29 @@ VirtualDir BISFactory::GetImageDirectory() const { u64 BISFactory::GetSystemNANDFreeSpace() const { const auto sys_dir = GetOrCreateDirectoryRelative(nand_root, "/system"); - if (sys_dir == nullptr) - return 0; + if (sys_dir == nullptr) { + return GetSystemNANDTotalSpace(); + } return GetSystemNANDTotalSpace() - sys_dir->GetSize(); } u64 BISFactory::GetSystemNANDTotalSpace() const { - return static_cast<u64>(Settings::values.nand_system_size); + return NAND_SYSTEM_SIZE; } u64 BISFactory::GetUserNANDFreeSpace() const { - const auto usr_dir = GetOrCreateDirectoryRelative(nand_root, "/user"); - if (usr_dir == nullptr) - return 0; - - return GetUserNANDTotalSpace() - usr_dir->GetSize(); + // For some reason games such as BioShock 1 checks whether this is exactly 0x680000000 bytes. + // Set the free space to be 1 MiB less than the total as a workaround to this issue. + return GetUserNANDTotalSpace() - 0x100000; } u64 BISFactory::GetUserNANDTotalSpace() const { - return static_cast<u64>(Settings::values.nand_user_size); + return NAND_USER_SIZE; } u64 BISFactory::GetFullNANDTotalSpace() const { - return static_cast<u64>(Settings::values.nand_total_size); + return NAND_TOTAL_SIZE; } VirtualDir BISFactory::GetBCATDirectory(u64 title_id) const { diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 27c1b0233..37351c561 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -547,6 +547,56 @@ InstallResult RegisteredCache::InstallEntry(const XCI& xci, bool overwrite_if_ex return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy); } +bool RegisteredCache::RemoveExistingEntry(u64 title_id) { + const auto delete_nca = [this](const NcaID& id) { + const auto path = GetRelativePathFromNcaID(id, false, true, false); + + if (dir->GetFileRelative(path) == nullptr) { + return false; + } + + Core::Crypto::SHA256Hash hash{}; + mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0); + const auto dirname = fmt::format("000000{:02X}", hash[0]); + + const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname); + + const auto res = dir2->DeleteFile(fmt::format("{}.nca", Common::HexToString(id, false))); + + return res; + }; + + // If an entry exists in the registered cache, remove it + if (HasEntry(title_id, ContentRecordType::Meta)) { + LOG_INFO(Loader, + "Previously installed entry (v{}) for title_id={:016X} detected! " + "Attempting to remove...", + GetEntryVersion(title_id).value_or(0), title_id); + // Get all the ncas associated with the current CNMT and delete them + const auto meta_old_id = + GetNcaIDFromMetadata(title_id, ContentRecordType::Meta).value_or(NcaID{}); + const auto program_id = + GetNcaIDFromMetadata(title_id, ContentRecordType::Program).value_or(NcaID{}); + const auto data_id = + GetNcaIDFromMetadata(title_id, ContentRecordType::Data).value_or(NcaID{}); + const auto control_id = + GetNcaIDFromMetadata(title_id, ContentRecordType::Control).value_or(NcaID{}); + const auto html_id = + GetNcaIDFromMetadata(title_id, ContentRecordType::HtmlDocument).value_or(NcaID{}); + const auto legal_id = + GetNcaIDFromMetadata(title_id, ContentRecordType::LegalInformation).value_or(NcaID{}); + + delete_nca(meta_old_id); + delete_nca(program_id); + delete_nca(data_id); + delete_nca(control_id); + delete_nca(html_id); + delete_nca(legal_id); + return true; + } + return false; +} + InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists, const VfsCopyFunction& copy) { const auto ncas = nsp.GetNCAsCollapsed(); @@ -560,31 +610,57 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex return InstallResult::ErrorMetaFailed; } - // Install Metadata File const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); const auto meta_id = Common::HexStringToArray<16>(meta_id_raw); - const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id); - if (res != InstallResult::Success) - return res; + if ((*meta_iter)->GetSubdirectories().empty()) { + LOG_ERROR(Loader, + "The file you are attempting to install does not contain a section0 within the " + "metadata NCA and is therefore malformed. Verify that the file is valid."); + return InstallResult::ErrorMetaFailed; + } - // Install all the other NCAs const auto section0 = (*meta_iter)->GetSubdirectories()[0]; + + if (section0->GetFiles().empty()) { + LOG_ERROR(Loader, + "The file you are attempting to install does not contain a CNMT within the " + "metadata NCA and is therefore malformed. Verify that the file is valid."); + return InstallResult::ErrorMetaFailed; + } + const auto cnmt_file = section0->GetFiles()[0]; const CNMT cnmt(cnmt_file); + + const auto title_id = cnmt.GetTitleID(); + const auto result = RemoveExistingEntry(title_id); + + // Install Metadata File + const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id); + if (res != InstallResult::Success) { + return res; + } + + // Install all the other NCAs for (const auto& record : cnmt.GetContentRecords()) { // Ignore DeltaFragments, they are not useful to us - if (record.type == ContentRecordType::DeltaFragment) + if (record.type == ContentRecordType::DeltaFragment) { continue; + } const auto nca = GetNCAFromNSPForID(nsp, record.nca_id); - if (nca == nullptr) + if (nca == nullptr) { return InstallResult::ErrorCopyFailed; + } const auto res2 = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id); - if (res2 != InstallResult::Success) + if (res2 != InstallResult::Success) { return res2; + } } Refresh(); + if (result) { + return InstallResult::OverwriteExisting; + } return InstallResult::Success; } @@ -610,8 +686,9 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type, mbedtls_sha256_ret(data.data(), data.size(), c_rec.hash.data(), 0); memcpy(&c_rec.nca_id, &c_rec.hash, 16); const CNMT new_cnmt(header, opt_header, {c_rec}, {}); - if (!RawInstallYuzuMeta(new_cnmt)) + if (!RawInstallYuzuMeta(new_cnmt)) { return InstallResult::ErrorMetaFailed; + } return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id); } @@ -649,8 +726,9 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti } auto out = dir->CreateFileRelative(path); - if (out == nullptr) + if (out == nullptr) { return InstallResult::ErrorCopyFailed; + } return copy(in, out, VFS_RC_LARGE_COPY_BLOCK) ? InstallResult::Success : InstallResult::ErrorCopyFailed; } diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h index f339cd17b..29cf0d40c 100644 --- a/src/core/file_sys/registered_cache.h +++ b/src/core/file_sys/registered_cache.h @@ -34,6 +34,7 @@ using VfsCopyFunction = std::function<bool(const VirtualFile&, const VirtualFile enum class InstallResult { Success, + OverwriteExisting, ErrorAlreadyExists, ErrorCopyFailed, ErrorMetaFailed, @@ -154,6 +155,9 @@ public: std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {}, std::optional<u64> title_id = {}) const override; + // Removes an existing entry based on title id + bool RemoveExistingEntry(u64 title_id); + // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure // there is a meta NCA and all of them are accessible. InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false, diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp index 5113a1ca6..6f732e4d8 100644 --- a/src/core/file_sys/sdmc_factory.cpp +++ b/src/core/file_sys/sdmc_factory.cpp @@ -10,6 +10,8 @@ namespace FileSys { +constexpr u64 SDMC_TOTAL_SIZE = 0x10000000000; // 1 TiB + SDMCFactory::SDMCFactory(VirtualDir dir_) : dir(std::move(dir_)), contents(std::make_unique<RegisteredCache>( GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"), @@ -46,7 +48,7 @@ u64 SDMCFactory::GetSDMCFreeSpace() const { } u64 SDMCFactory::GetSDMCTotalSpace() const { - return static_cast<u64>(Settings::values.sdmc_size); + return SDMC_TOTAL_SIZE; } } // namespace FileSys diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index e21300a7c..96ce5957c 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -112,19 +112,26 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_ const auto new_path = FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault); - if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || - FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) - return nullptr; - if (cache.find(old_path) != cache.end()) { - auto cached = cache[old_path]; - if (!cached.expired()) { - auto file = cached.lock(); - file->Open(new_path, "r+b"); - cache.erase(old_path); - cache[new_path] = file; + auto file = cache[old_path].lock(); + + if (!cache[old_path].expired()) { + file->Close(); + } + + if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || + FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) { + return nullptr; } + + cache.erase(old_path); + file->Open(new_path, "r+b"); + cache[new_path] = file; + } else { + UNREACHABLE(); + return nullptr; } + return OpenFile(new_path, Mode::ReadWrite); } diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 35448b576..fb30b6f8b 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -8,7 +8,9 @@ #include "core/core.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" namespace Kernel { @@ -22,7 +24,7 @@ constexpr u16 GetGeneration(Handle handle) { } } // Anonymous namespace -HandleTable::HandleTable() { +HandleTable::HandleTable(KernelCore& kernel) : kernel{kernel} { Clear(); } @@ -103,9 +105,9 @@ bool HandleTable::IsValid(Handle handle) const { std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const { if (handle == CurrentThread) { - return SharedFrom(GetCurrentThread()); + return SharedFrom(kernel.CurrentScheduler().GetCurrentThread()); } else if (handle == CurrentProcess) { - return SharedFrom(Core::System::GetInstance().CurrentProcess()); + return SharedFrom(kernel.CurrentProcess()); } if (!IsValid(handle)) { diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index 8029660ed..c9dab8cdd 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h @@ -14,6 +14,8 @@ namespace Kernel { +class KernelCore; + enum KernelHandle : Handle { InvalidHandle = 0, CurrentThread = 0xFFFF8000, @@ -48,7 +50,7 @@ public: /// This is the maximum limit of handles allowed per process in Horizon static constexpr std::size_t MAX_COUNT = 1024; - HandleTable(); + explicit HandleTable(KernelCore& kernel); ~HandleTable(); /** @@ -134,6 +136,9 @@ private: /// Head of the free slots linked list. u16 next_free_slot = 0; + + /// Underlying kernel instance that this handle table operates under. + KernelCore& kernel; }; } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1f2af7a1b..e1c7a0f3b 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -50,7 +50,8 @@ namespace Kernel { struct KernelCore::Impl { explicit Impl(Core::System& system, KernelCore& kernel) - : global_scheduler{kernel}, synchronization{system}, time_manager{system}, system{system} {} + : global_scheduler{kernel}, synchronization{system}, time_manager{system}, + global_handle_table{kernel}, system{system} {} void SetMulticore(bool is_multicore) { this->is_multicore = is_multicore; @@ -160,13 +161,14 @@ struct KernelCore::Impl { void InitializeSuspendThreads() { for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { std::string name = "Suspend Thread Id:" + std::to_string(i); - std::function<void(void*)> init_func = - system.GetCpuManager().GetSuspendThreadStartFunc(); + std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc(); void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); - ThreadType type = + const auto type = static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_SUSPEND); - auto thread_res = Thread::Create(system, type, name, 0, 0, 0, static_cast<u32>(i), 0, - nullptr, std::move(init_func), init_func_parameter); + auto thread_res = + Thread::Create(system, type, std::move(name), 0, 0, 0, static_cast<u32>(i), 0, + nullptr, std::move(init_func), init_func_parameter); + suspend_threads[i] = std::move(thread_res).Unwrap(); } } @@ -307,7 +309,7 @@ struct KernelCore::Impl { // This is the kernel's handle table or supervisor handle table which // stores all the objects in place. - Kernel::HandleTable global_handle_table; + HandleTable global_handle_table; /// Map of named ports managed by the kernel, which can be retrieved using /// the ConnectToPort SVC. diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 49bd47e89..16285c3f0 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -9,6 +9,7 @@ #include <string> #include <unordered_map> #include <vector> +#include "core/arm/cpu_interrupt_handler.h" #include "core/hardware_properties.h" #include "core/hle/kernel/memory/memory_types.h" #include "core/hle/kernel/object.h" diff --git a/src/core/hle/kernel/memory/address_space_info.cpp b/src/core/hle/kernel/memory/address_space_info.cpp index a523a2502..e4288cab4 100644 --- a/src/core/hle/kernel/memory/address_space_info.cpp +++ b/src/core/hle/kernel/memory/address_space_info.cpp @@ -29,40 +29,39 @@ enum : u64 { // clang-format off constexpr std::array<AddressSpaceInfo, 13> AddressSpaceInfos{{ - { 32 /*bit_width*/, Size_2_MB /*addr*/, Size_1_GB - Size_2_MB /*size*/, AddressSpaceInfo::Type::Is32Bit, }, - { 32 /*bit_width*/, Size_1_GB /*addr*/, Size_4_GB - Size_1_GB /*size*/, AddressSpaceInfo::Type::Small64Bit, }, - { 32 /*bit_width*/, Invalid /*addr*/, Size_1_GB /*size*/, AddressSpaceInfo::Type::Heap, }, - { 32 /*bit_width*/, Invalid /*addr*/, Size_1_GB /*size*/, AddressSpaceInfo::Type::Alias, }, - { 36 /*bit_width*/, Size_128_MB /*addr*/, Size_2_GB - Size_128_MB /*size*/, AddressSpaceInfo::Type::Is32Bit, }, - { 36 /*bit_width*/, Size_2_GB /*addr*/, Size_64_GB - Size_2_GB /*size*/, AddressSpaceInfo::Type::Small64Bit, }, - { 36 /*bit_width*/, Invalid /*addr*/, Size_6_GB /*size*/, AddressSpaceInfo::Type::Heap, }, - { 36 /*bit_width*/, Invalid /*addr*/, Size_6_GB /*size*/, AddressSpaceInfo::Type::Alias, }, - { 39 /*bit_width*/, Size_128_MB /*addr*/, Size_512_GB - Size_128_MB /*size*/, AddressSpaceInfo::Type::Large64Bit, }, - { 39 /*bit_width*/, Invalid /*addr*/, Size_64_GB /*size*/, AddressSpaceInfo::Type::Is32Bit }, - { 39 /*bit_width*/, Invalid /*addr*/, Size_6_GB /*size*/, AddressSpaceInfo::Type::Heap, }, - { 39 /*bit_width*/, Invalid /*addr*/, Size_64_GB /*size*/, AddressSpaceInfo::Type::Alias, }, - { 39 /*bit_width*/, Invalid /*addr*/, Size_2_GB /*size*/, AddressSpaceInfo::Type::Stack, }, + { .bit_width = 32, .address = Size_2_MB , .size = Size_1_GB - Size_2_MB , .type = AddressSpaceInfo::Type::Is32Bit, }, + { .bit_width = 32, .address = Size_1_GB , .size = Size_4_GB - Size_1_GB , .type = AddressSpaceInfo::Type::Small64Bit, }, + { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = AddressSpaceInfo::Type::Heap, }, + { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = AddressSpaceInfo::Type::Alias, }, + { .bit_width = 36, .address = Size_128_MB, .size = Size_2_GB - Size_128_MB, .type = AddressSpaceInfo::Type::Is32Bit, }, + { .bit_width = 36, .address = Size_2_GB , .size = Size_64_GB - Size_2_GB , .type = AddressSpaceInfo::Type::Small64Bit, }, + { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = AddressSpaceInfo::Type::Heap, }, + { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = AddressSpaceInfo::Type::Alias, }, + { .bit_width = 39, .address = Size_128_MB, .size = Size_512_GB - Size_128_MB, .type = AddressSpaceInfo::Type::Large64Bit, }, + { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = AddressSpaceInfo::Type::Is32Bit }, + { .bit_width = 39, .address = Invalid , .size = Size_6_GB , .type = AddressSpaceInfo::Type::Heap, }, + { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = AddressSpaceInfo::Type::Alias, }, + { .bit_width = 39, .address = Invalid , .size = Size_2_GB , .type = AddressSpaceInfo::Type::Stack, }, }}; // clang-format on constexpr bool IsAllowedIndexForAddress(std::size_t index) { - return index < std::size(AddressSpaceInfos) && AddressSpaceInfos[index].GetAddress() != Invalid; + return index < AddressSpaceInfos.size() && AddressSpaceInfos[index].address != Invalid; } -constexpr std::array<std::size_t, static_cast<std::size_t>(AddressSpaceInfo::Type::Count)> - AddressSpaceIndices32Bit{ - 0, 1, 0, 2, 0, 3, - }; +using IndexArray = std::array<std::size_t, static_cast<std::size_t>(AddressSpaceInfo::Type::Count)>; -constexpr std::array<std::size_t, static_cast<std::size_t>(AddressSpaceInfo::Type::Count)> - AddressSpaceIndices36Bit{ - 4, 5, 4, 6, 4, 7, - }; +constexpr IndexArray AddressSpaceIndices32Bit{ + 0, 1, 0, 2, 0, 3, +}; + +constexpr IndexArray AddressSpaceIndices36Bit{ + 4, 5, 4, 6, 4, 7, +}; -constexpr std::array<std::size_t, static_cast<std::size_t>(AddressSpaceInfo::Type::Count)> - AddressSpaceIndices39Bit{ - 9, 8, 8, 10, 12, 11, - }; +constexpr IndexArray AddressSpaceIndices39Bit{ + 9, 8, 8, 10, 12, 11, +}; constexpr bool IsAllowed32BitType(AddressSpaceInfo::Type type) { return type < AddressSpaceInfo::Type::Count && type != AddressSpaceInfo::Type::Large64Bit && @@ -80,37 +79,37 @@ constexpr bool IsAllowed39BitType(AddressSpaceInfo::Type type) { } // namespace -u64 AddressSpaceInfo::GetAddressSpaceStart(std::size_t width, AddressSpaceInfo::Type type) { +u64 AddressSpaceInfo::GetAddressSpaceStart(std::size_t width, Type type) { const std::size_t index{static_cast<std::size_t>(type)}; switch (width) { case 32: ASSERT(IsAllowed32BitType(type)); ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices32Bit[index])); - return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].GetAddress(); + return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].address; case 36: ASSERT(IsAllowed36BitType(type)); ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices36Bit[index])); - return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].GetAddress(); + return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].address; case 39: ASSERT(IsAllowed39BitType(type)); ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices39Bit[index])); - return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].GetAddress(); + return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].address; } UNREACHABLE(); } -std::size_t AddressSpaceInfo::GetAddressSpaceSize(std::size_t width, AddressSpaceInfo::Type type) { +std::size_t AddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type) { const std::size_t index{static_cast<std::size_t>(type)}; switch (width) { case 32: ASSERT(IsAllowed32BitType(type)); - return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].GetSize(); + return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].size; case 36: ASSERT(IsAllowed36BitType(type)); - return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].GetSize(); + return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].size; case 39: ASSERT(IsAllowed39BitType(type)); - return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].GetSize(); + return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].size; } UNREACHABLE(); } diff --git a/src/core/hle/kernel/memory/address_space_info.h b/src/core/hle/kernel/memory/address_space_info.h index c479890be..a4e6e91e5 100644 --- a/src/core/hle/kernel/memory/address_space_info.h +++ b/src/core/hle/kernel/memory/address_space_info.h @@ -11,8 +11,7 @@ namespace Kernel::Memory { -class AddressSpaceInfo final : NonCopyable { -public: +struct AddressSpaceInfo final { enum class Type : u32 { Is32Bit = 0, Small64Bit = 1, @@ -23,31 +22,13 @@ public: Count, }; -private: - std::size_t bit_width{}; - std::size_t addr{}; - std::size_t size{}; - Type type{}; - -public: static u64 GetAddressSpaceStart(std::size_t width, Type type); static std::size_t GetAddressSpaceSize(std::size_t width, Type type); - constexpr AddressSpaceInfo(std::size_t bit_width, std::size_t addr, std::size_t size, Type type) - : bit_width{bit_width}, addr{addr}, size{size}, type{type} {} - - constexpr std::size_t GetWidth() const { - return bit_width; - } - constexpr std::size_t GetAddress() const { - return addr; - } - constexpr std::size_t GetSize() const { - return size; - } - constexpr Type GetType() const { - return type; - } + const std::size_t bit_width{}; + const std::size_t address{}; + const std::size_t size{}; + const Type type{}; }; } // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/memory_layout.h b/src/core/hle/kernel/memory/memory_layout.h index 830c6f0d7..9b3d6267a 100644 --- a/src/core/hle/kernel/memory/memory_layout.h +++ b/src/core/hle/kernel/memory/memory_layout.h @@ -66,8 +66,6 @@ private: const MemoryRegion application; const MemoryRegion applet; const MemoryRegion system; - - const PAddr start_address{}; }; } // namespace Kernel::Memory diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index c6fcb56ad..ff9d9248b 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -408,7 +408,7 @@ void Process::LoadModule(CodeSet code_set, VAddr base_addr) { Process::Process(Core::System& system) : SynchronizationObject{system.Kernel()}, page_table{std::make_unique<Memory::PageTable>( system)}, - address_arbiter{system}, mutex{system}, system{system} {} + handle_table{system.Kernel()}, address_arbiter{system}, mutex{system}, system{system} {} Process::~Process() = default; diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 9dabe3568..f45cb5674 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -382,12 +382,6 @@ private: /// List of threads waiting for a condition variable std::unordered_map<VAddr, std::list<std::shared_ptr<Thread>>> cond_var_threads; - /// System context - Core::System& system; - - /// Name of this process - std::string name; - /// Address of the top of the main thread's stack VAddr main_thread_stack_top{}; @@ -399,6 +393,12 @@ private: /// Process total image size std::size_t image_size{}; + + /// Name of this process + std::string name; + + /// System context + Core::System& system; }; } // namespace Kernel diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 7b929781c..f93e5e4b0 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -802,7 +802,7 @@ void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { void Scheduler::Initialize() { std::string name = "Idle Thread Id:" + std::to_string(core_id); - std::function<void(void*)> init_func = system.GetCpuManager().GetIdleThreadStartFunc(); + std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc(); void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); ThreadType type = static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE); auto thread_res = Thread::Create(system, type, name, 0, 64, 0, static_cast<u32>(core_id), 0, diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 2b1092697..d132aba34 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -13,16 +13,8 @@ #include "common/logging/log.h" #include "common/thread_queue_list.h" #include "core/arm/arm_interface.h" -#ifdef ARCHITECTURE_x86_64 -#include "core/arm/dynarmic/arm_dynarmic_32.h" -#include "core/arm/dynarmic/arm_dynarmic_64.h" -#endif -#include "core/arm/cpu_interrupt_handler.h" -#include "core/arm/exclusive_monitor.h" #include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" -#include "core/core_timing.h" -#include "core/core_timing_util.h" #include "core/cpu_manager.h" #include "core/hardware_properties.h" #include "core/hle/kernel/errors.h" @@ -36,6 +28,11 @@ #include "core/hle/result.h" #include "core/memory.h" +#ifdef ARCHITECTURE_x86_64 +#include "core/arm/dynarmic/arm_dynarmic_32.h" +#include "core/arm/dynarmic/arm_dynarmic_64.h" +#endif + namespace Kernel { bool Thread::ShouldWait(const Thread* thread) const { @@ -158,7 +155,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy std::string name, VAddr entry_point, u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process) { - std::function<void(void*)> init_func = system.GetCpuManager().GetGuestThreadStartFunc(); + std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc(); void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top, owner_process, std::move(init_func), init_func_parameter); @@ -540,13 +537,4 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { return RESULT_SUCCESS; } -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * Gets the current thread - */ -Thread* GetCurrentThread() { - return Core::System::GetInstance().CurrentScheduler().GetCurrentThread(); -} - } // namespace Kernel diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index c0342c462..9808767e5 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -680,9 +680,4 @@ private: std::string name; }; -/** - * Gets the current thread - */ -Thread* GetCurrentThread(); - } // namespace Kernel diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 256449aa7..4e7a0bec9 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -1407,7 +1407,19 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { u32 supported_languages = 0; FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()}; - const auto res = pm.GetControlMetadata(); + const auto res = [this] { + const auto title_id = system.CurrentProcess()->GetTitleID(); + + FileSys::PatchManager pm{title_id}; + auto res = pm.GetControlMetadata(); + if (res.first != nullptr) { + return res; + } + + FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id)}; + return pm_update.GetControlMetadata(); + }(); + if (res.first != nullptr) { supported_languages = res.first->GetSupportedLanguages(); } diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index f19affce7..11aa74828 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp @@ -121,11 +121,83 @@ public: {39, nullptr, "PrepareShutdown"}, {40, nullptr, "ListApplyDeltaTask"}, {41, nullptr, "ClearNotEnoughSpaceStateOfApplyDeltaTask"}, - {42, nullptr, "Unknown1"}, - {43, nullptr, "Unknown2"}, - {44, nullptr, "Unknown3"}, - {45, nullptr, "Unknown4"}, - {46, nullptr, "Unknown5"}, + {42, nullptr, "Unknown42"}, + {43, nullptr, "Unknown43"}, + {44, nullptr, "Unknown44"}, + {45, nullptr, "Unknown45"}, + {46, nullptr, "Unknown46"}, + {47, nullptr, "Unknown47"}, + {48, nullptr, "Unknown48"}, + {49, nullptr, "Unknown49"}, + {50, nullptr, "Unknown50"}, + {51, nullptr, "Unknown51"}, + {52, nullptr, "Unknown52"}, + {53, nullptr, "Unknown53"}, + {54, nullptr, "Unknown54"}, + {55, nullptr, "Unknown55"}, + {56, nullptr, "Unknown56"}, + {57, nullptr, "Unknown57"}, + {58, nullptr, "Unknown58"}, + {59, nullptr, "Unknown59"}, + {60, nullptr, "Unknown60"}, + {61, nullptr, "Unknown61"}, + {62, nullptr, "Unknown62"}, + {63, nullptr, "Unknown63"}, + {64, nullptr, "Unknown64"}, + {65, nullptr, "Unknown65"}, + {66, nullptr, "Unknown66"}, + {67, nullptr, "Unknown67"}, + {68, nullptr, "Unknown68"}, + {69, nullptr, "Unknown69"}, + {70, nullptr, "Unknown70"}, + {71, nullptr, "Unknown71"}, + {72, nullptr, "Unknown72"}, + {73, nullptr, "Unknown73"}, + {74, nullptr, "Unknown74"}, + {75, nullptr, "Unknown75"}, + {76, nullptr, "Unknown76"}, + {77, nullptr, "Unknown77"}, + {78, nullptr, "Unknown78"}, + {79, nullptr, "Unknown79"}, + {80, nullptr, "Unknown80"}, + {81, nullptr, "Unknown81"}, + {82, nullptr, "Unknown82"}, + {83, nullptr, "Unknown83"}, + {84, nullptr, "Unknown84"}, + {85, nullptr, "Unknown85"}, + {86, nullptr, "Unknown86"}, + {87, nullptr, "Unknown87"}, + {88, nullptr, "Unknown88"}, + {89, nullptr, "Unknown89"}, + {90, nullptr, "Unknown90"}, + {91, nullptr, "Unknown91"}, + {92, nullptr, "Unknown92"}, + {93, nullptr, "Unknown93"}, + {94, nullptr, "Unknown94"}, + {95, nullptr, "Unknown95"}, + {96, nullptr, "Unknown96"}, + {97, nullptr, "Unknown97"}, + {98, nullptr, "Unknown98"}, + {99, nullptr, "Unknown99"}, + {100, nullptr, "Unknown100"}, + {101, nullptr, "Unknown101"}, + {102, nullptr, "Unknown102"}, + {103, nullptr, "Unknown103"}, + {104, nullptr, "Unknown104"}, + {105, nullptr, "Unknown105"}, + {106, nullptr, "Unknown106"}, + {107, nullptr, "Unknown107"}, + {108, nullptr, "Unknown108"}, + {109, nullptr, "Unknown109"}, + {110, nullptr, "Unknown110"}, + {111, nullptr, "Unknown111"}, + {112, nullptr, "Unknown112"}, + {113, nullptr, "Unknown113"}, + {114, nullptr, "Unknown114"}, + {115, nullptr, "Unknown115"}, + {116, nullptr, "Unknown116"}, + {117, nullptr, "Unknown117"}, + {118, nullptr, "Unknown118"}, }; // clang-format on @@ -142,6 +214,7 @@ public: {1, nullptr, "RefreshDebugAvailability"}, {2, nullptr, "ClearDebugResponse"}, {3, nullptr, "RegisterDebugResponse"}, + {4, nullptr, "IsLargeResourceAvailable"}, }; // clang-format on @@ -164,6 +237,8 @@ public: static const FunctionInfo functions[] = { {0, nullptr, "RequestDeviceAuthenticationToken"}, {1, nullptr, "RequestCachedDeviceAuthenticationToken"}, + {2, nullptr, "RequestEdgeToken"}, + {3, nullptr, "RequestCachedEdgeToken"}, {100, nullptr, "RequestRegisterDeviceAccount"}, {101, nullptr, "RequestUnregisterDeviceAccount"}, {102, nullptr, "RequestDeviceAccountStatus"}, @@ -181,7 +256,8 @@ public: {305, nullptr, "RequestCreateVirtualAccount"}, {306, nullptr, "RequestDeviceLinkStatus"}, {400, nullptr, "GetAccountByVirtualAccount"}, - {500, nullptr, "RequestSyncTicket"}, + {401, nullptr, "GetVirtualAccount"}, + {500, nullptr, "RequestSyncTicketLegacy"}, {501, nullptr, "RequestDownloadTicket"}, {502, nullptr, "RequestDownloadTicketForPrepurchasedContents"}, {503, nullptr, "RequestSyncTicket"}, diff --git a/src/core/hle/service/npns/npns.cpp b/src/core/hle/service/npns/npns.cpp index f38d01084..8fa16fb08 100644 --- a/src/core/hle/service/npns/npns.cpp +++ b/src/core/hle/service/npns/npns.cpp @@ -30,6 +30,7 @@ public: {23, nullptr, "DestroyToken"}, {24, nullptr, "DestroyTokenWithApplicationId"}, {25, nullptr, "QueryIsTokenValid"}, + {26, nullptr, "ListenToMyApplicationId"}, {31, nullptr, "UploadTokenToBaaS"}, {32, nullptr, "DestroyTokenForBaaS"}, {33, nullptr, "CreateTokenForBaaS"}, diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 6cfa9666d..886450be2 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -104,7 +104,7 @@ IApplicationManagerInterface::IApplicationManagerInterface() {94, nullptr, "LaunchApplication"}, {95, nullptr, "GetApplicationLaunchInfo"}, {96, nullptr, "AcquireApplicationLaunchInfo"}, - {97, nullptr, "GetMainApplicationProgramIndex2"}, + {97, nullptr, "GetMainApplicationProgramIndexByApplicationLaunchInfo"}, {98, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, {99, nullptr, "LaunchDevMenu"}, {100, nullptr, "ResetToFactorySettings"}, @@ -254,7 +254,7 @@ IApplicationManagerInterface::IApplicationManagerInterface() {2170, nullptr, "GetRightsEnvironmentStatus"}, {2171, nullptr, "GetRightsEnvironmentStatusChangedEvent"}, {2180, nullptr, "RequestExtendRightsInRightsEnvironment"}, - {2181, nullptr, "GetLastResultOfExtendRightsInRightsEnvironment"}, + {2181, nullptr, "GetResultOfExtendRightsInRightsEnvironment"}, {2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"}, {2190, nullptr, "GetRightsEnvironmentHandleForApplication"}, {2199, nullptr, "GetRightsEnvironmentCountForDebug"}, @@ -446,8 +446,8 @@ IApplicationVersionInterface::IApplicationVersionInterface() IApplicationVersionInterface::~IApplicationVersionInterface() = default; -IContentManagerInterface::IContentManagerInterface() - : ServiceFramework{"IContentManagerInterface"} { +IContentManagementInterface::IContentManagementInterface() + : ServiceFramework{"IContentManagementInterface"} { // clang-format off static const FunctionInfo functions[] = { {11, nullptr, "CalculateApplicationOccupiedSize"}, @@ -464,7 +464,7 @@ IContentManagerInterface::IContentManagerInterface() RegisterHandlers(functions); } -IContentManagerInterface::~IContentManagerInterface() = default; +IContentManagementInterface::~IContentManagementInterface() = default; IDocumentInterface::IDocumentInterface() : ServiceFramework{"IDocumentInterface"} { // clang-format off @@ -546,7 +546,7 @@ NS::NS(const char* name) : ServiceFramework{name} { {7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"}, {7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"}, {7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"}, - {7998, &NS::PushInterface<IContentManagerInterface>, "GetContentManagementInterface"}, + {7998, &NS::PushInterface<IContentManagementInterface>, "GetContentManagementInterface"}, {7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"}, }; // clang-format on @@ -573,9 +573,9 @@ public: {6, nullptr, "TerminateApplication"}, {7, nullptr, "PrepareLaunchProgramFromHost"}, {8, nullptr, "LaunchApplication"}, - {9, nullptr, "LaunchApplicationWithStorageId"}, - {10, nullptr, "TerminateApplication2"}, - {11, nullptr, "GetRunningApplicationProcessId"}, + {9, nullptr, "LaunchApplicationWithStorageIdForDevelop"}, + {10, nullptr, "IsSystemMemoryResourceLimitBoosted"}, + {11, nullptr, "GetRunningApplicationProcessIdForDevelop"}, {12, nullptr, "SetCurrentApplicationRightsEnvironmentCanBeActive"}, {13, nullptr, "CreateApplicationResourceForDevelop"}, {14, nullptr, "IsPreomiaForDevelop"}, @@ -637,6 +637,10 @@ public: {9, nullptr, "GetSystemUpdateNotificationEventForContentDelivery"}, {10, nullptr, "NotifySystemUpdateForContentDelivery"}, {11, nullptr, "PrepareShutdown"}, + {12, nullptr, "Unknown12"}, + {13, nullptr, "Unknown13"}, + {14, nullptr, "Unknown14"}, + {15, nullptr, "Unknown15"}, {16, nullptr, "DestroySystemUpdateTask"}, {17, nullptr, "RequestSendSystemUpdate"}, {18, nullptr, "GetSendSystemUpdateProgress"}, diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index 13a64ad88..c2554b878 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h @@ -40,10 +40,10 @@ public: ~IApplicationVersionInterface() override; }; -class IContentManagerInterface final : public ServiceFramework<IContentManagerInterface> { +class IContentManagementInterface final : public ServiceFramework<IContentManagementInterface> { public: - explicit IContentManagerInterface(); - ~IContentManagerInterface() override; + explicit IContentManagementInterface(); + ~IContentManagementInterface() override; }; class IDocumentInterface final : public ServiceFramework<IDocumentInterface> { diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 6efdf1606..40838a225 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp @@ -163,7 +163,7 @@ PL_U::PL_U(Core::System& system) {5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"}, {6, nullptr, "GetSharedFontInOrderOfPriorityForSystem"}, {100, nullptr, "RequestApplicationFunctionAuthorization"}, - {101, nullptr, "RequestApplicationFunctionAuthorizationForSystem"}, + {101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"}, {102, nullptr, "RequestApplicationFunctionAuthorizationByApplicationId"}, {1000, nullptr, "LoadNgWordDataForPlatformRegionChina"}, {1001, nullptr, "GetNgWordDataSizeForPlatformRegionChina"}, diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index c8ea6c661..deaf0808b 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp @@ -144,7 +144,7 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { } } -void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { +void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; pid = rp.Pop<u64>(); LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid); @@ -154,7 +154,7 @@ void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { rb.Push<u32>(0); } -void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) { +void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_NVDRV, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; @@ -187,13 +187,14 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) {4, &NVDRV::QueryEvent, "QueryEvent"}, {5, nullptr, "MapSharedMem"}, {6, &NVDRV::GetStatus, "GetStatus"}, - {7, nullptr, "ForceSetClientPID"}, - {8, &NVDRV::SetClientPID, "SetClientPID"}, + {7, nullptr, "SetAruidForTest"}, + {8, &NVDRV::SetAruid, "SetAruid"}, {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"}, {10, nullptr, "InitializeDevtools"}, {11, &NVDRV::Ioctl2, "Ioctl2"}, {12, &NVDRV::Ioctl3, "Ioctl3"}, - {13, &NVDRV::FinishInitialize, "FinishInitialize"}, + {13, &NVDRV::SetGraphicsFirmwareMemoryMarginEnabled, + "SetGraphicsFirmwareMemoryMarginEnabled"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index 9269ce00c..72e17a728 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h @@ -29,8 +29,8 @@ private: void Close(Kernel::HLERequestContext& ctx); void Initialize(Kernel::HLERequestContext& ctx); void QueryEvent(Kernel::HLERequestContext& ctx); - void SetClientPID(Kernel::HLERequestContext& ctx); - void FinishInitialize(Kernel::HLERequestContext& ctx); + void SetAruid(Kernel::HLERequestContext& ctx); + void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx); void GetStatus(Kernel::HLERequestContext& ctx); void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version); diff --git a/src/core/hle/service/nvdrv/nvmemp.cpp b/src/core/hle/service/nvdrv/nvmemp.cpp index b7b8b7a1b..73b37e805 100644 --- a/src/core/hle/service/nvdrv/nvmemp.cpp +++ b/src/core/hle/service/nvdrv/nvmemp.cpp @@ -10,19 +10,19 @@ namespace Service::Nvidia { NVMEMP::NVMEMP() : ServiceFramework("nvmemp") { static const FunctionInfo functions[] = { - {0, &NVMEMP::Cmd0, "Cmd0"}, - {1, &NVMEMP::Cmd1, "Cmd1"}, + {0, &NVMEMP::Open, "Open"}, + {1, &NVMEMP::GetAruid, "GetAruid"}, }; RegisterHandlers(functions); } NVMEMP::~NVMEMP() = default; -void NVMEMP::Cmd0(Kernel::HLERequestContext& ctx) { +void NVMEMP::Open(Kernel::HLERequestContext& ctx) { UNIMPLEMENTED(); } -void NVMEMP::Cmd1(Kernel::HLERequestContext& ctx) { +void NVMEMP::GetAruid(Kernel::HLERequestContext& ctx) { UNIMPLEMENTED(); } diff --git a/src/core/hle/service/nvdrv/nvmemp.h b/src/core/hle/service/nvdrv/nvmemp.h index 6eafb1346..c453ee4db 100644 --- a/src/core/hle/service/nvdrv/nvmemp.h +++ b/src/core/hle/service/nvdrv/nvmemp.h @@ -14,8 +14,8 @@ public: ~NVMEMP() override; private: - void Cmd0(Kernel::HLERequestContext& ctx); - void Cmd1(Kernel::HLERequestContext& ctx); + void Open(Kernel::HLERequestContext& ctx); + void GetAruid(Kernel::HLERequestContext& ctx); }; } // namespace Service::Nvidia diff --git a/src/core/hle/service/pcie/pcie.cpp b/src/core/hle/service/pcie/pcie.cpp index 39cf05eba..c568a0adc 100644 --- a/src/core/hle/service/pcie/pcie.cpp +++ b/src/core/hle/service/pcie/pcie.cpp @@ -36,6 +36,9 @@ public: {18, nullptr, "ReleaseIrq"}, {19, nullptr, "SetIrqEnable"}, {20, nullptr, "SetAspmEnable"}, + {21, nullptr, "SetResetUponResumeEnable"}, + {22, nullptr, "Unknown22"}, + {23, nullptr, "Unknown23"}, }; // clang-format on diff --git a/src/core/hle/service/pcv/pcv.cpp b/src/core/hle/service/pcv/pcv.cpp index d6891a659..8bfc0276e 100644 --- a/src/core/hle/service/pcv/pcv.cpp +++ b/src/core/hle/service/pcv/pcv.cpp @@ -42,6 +42,9 @@ public: {24, nullptr, "GetModuleStateTable"}, {25, nullptr, "GetPowerDomainStateTable"}, {26, nullptr, "GetFuseInfo"}, + {27, nullptr, "GetDramId"}, + {28, nullptr, "IsPoweredOn"}, + {29, nullptr, "GetVoltage"}, }; // clang-format on diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index 809eca0ab..f43122ad2 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp @@ -78,13 +78,13 @@ public: : ServiceFramework{"pm:dmnt"}, kernel(kernel) { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "GetDebugProcesses"}, - {1, nullptr, "StartDebugProcess"}, - {2, &DebugMonitor::GetTitlePid, "GetTitlePid"}, - {3, nullptr, "EnableDebugForTitleId"}, - {4, &DebugMonitor::GetApplicationPid, "GetApplicationPid"}, - {5, nullptr, "EnableDebugForApplication"}, - {6, nullptr, "DisableDebug"}, + {0, nullptr, "GetJitDebugProcessIdList"}, + {1, nullptr, "StartProcess"}, + {2, &DebugMonitor::GetProcessId, "GetProcessId"}, + {3, nullptr, "HookToCreateProcess"}, + {4, &DebugMonitor::GetApplicationProcessId, "GetApplicationProcessId"}, + {5, nullptr, "HookToCreateApplicationProgress"}, + {6, nullptr, "ClearHook"}, }; // clang-format on @@ -92,7 +92,7 @@ public: } private: - void GetTitlePid(Kernel::HLERequestContext& ctx) { + void GetProcessId(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto title_id = rp.PopRaw<u64>(); @@ -114,7 +114,7 @@ private: rb.Push((*process)->GetProcessID()); } - void GetApplicationPid(Kernel::HLERequestContext& ctx) { + void GetApplicationProcessId(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_PM, "called"); GetApplicationPidGeneric(ctx, kernel.GetProcessList()); } @@ -163,15 +163,15 @@ public: : ServiceFramework{"pm:shell"}, kernel(kernel) { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "LaunchProcess"}, - {1, nullptr, "TerminateProcessByPid"}, - {2, nullptr, "TerminateProcessByTitleId"}, - {3, nullptr, "GetProcessEventWaiter"}, - {4, nullptr, "GetProcessEventType"}, + {0, nullptr, "LaunchProgram"}, + {1, nullptr, "TerminateProcess"}, + {2, nullptr, "TerminateProgram"}, + {3, nullptr, "GetProcessEventHandle"}, + {4, nullptr, "GetProcessEventInfo"}, {5, nullptr, "NotifyBootFinished"}, - {6, &Shell::GetApplicationPid, "GetApplicationPid"}, + {6, &Shell::GetApplicationProcessIdForShell, "GetApplicationProcessIdForShell"}, {7, nullptr, "BoostSystemMemoryResourceLimit"}, - {8, nullptr, "EnableAdditionalSystemThreads"}, + {8, nullptr, "BoostApplicationThreadResourceLimit"}, {9, nullptr, "GetBootFinishedEventHandle"}, }; // clang-format on @@ -180,7 +180,7 @@ public: } private: - void GetApplicationPid(Kernel::HLERequestContext& ctx) { + void GetApplicationProcessIdForShell(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_PM, "called"); GetApplicationPidGeneric(ctx, kernel.GetProcessList()); } diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index 67833d9af..cde3312da 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp @@ -42,6 +42,11 @@ public: {40101, nullptr, "SetUserAgreementCheckEnabled"}, {50100, nullptr, "ReadAllApplicationReportFiles"}, {90100, nullptr, "ReadAllReportFiles"}, + {90101, nullptr, "Unknown90101"}, + {90102, nullptr, "Unknown90102"}, + {90200, nullptr, "GetStatistics"}, + {90201, nullptr, "GetThroughputHistory"}, + {90300, nullptr, "GetLastUploadError"}, }; // clang-format on diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp index 53ec6b031..99e1c9042 100644 --- a/src/core/hle/service/psc/psc.cpp +++ b/src/core/hle/service/psc/psc.cpp @@ -24,6 +24,8 @@ public: {4, nullptr, "Cancel"}, {5, nullptr, "PrintModuleInformation"}, {6, nullptr, "GetModuleInformation"}, + {10, nullptr, "Unknown10"}, + {11, nullptr, "Unknown11"}, }; // clang-format on diff --git a/src/core/hle/service/ptm/psm.cpp b/src/core/hle/service/ptm/psm.cpp index 12d154ecf..6d9e6bd09 100644 --- a/src/core/hle/service/ptm/psm.cpp +++ b/src/core/hle/service/ptm/psm.cpp @@ -35,6 +35,7 @@ public: {15, nullptr, "GetBatteryAgePercentage"}, {16, nullptr, "GetBatteryChargeInfoEvent"}, {17, nullptr, "GetBatteryChargeInfoFields"}, + {18, nullptr, "GetBatteryChargeCalibratedEvent"}, }; // clang-format on diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index 9cca84b31..972aaa6d9 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp @@ -12,7 +12,7 @@ namespace Service::SM { -void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { +void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId()); ctx.Session()->ConvertToDomain(); @@ -22,7 +22,7 @@ void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { rb.Push<u32>(1); // Converted sessions start with 1 request handler } -void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { +void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong // and that we probably want to actually make an entirely new Session, but we still need to // verify this on hardware. @@ -33,10 +33,10 @@ void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { rb.PushMoveObjects(ctx.Session()->GetParent()->Client()); } -void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service, "(STUBBED) called, using DuplicateSession"); +void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) called, using CloneCurrentObject"); - DuplicateSession(ctx); + CloneCurrentObject(ctx); } void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { @@ -47,13 +47,14 @@ void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { rb.Push<u16>(0x1000); } +// https://switchbrew.org/wiki/IPC_Marshalling Controller::Controller() : ServiceFramework("IpcController") { static const FunctionInfo functions[] = { - {0x00000000, &Controller::ConvertSessionToDomain, "ConvertSessionToDomain"}, - {0x00000001, nullptr, "ConvertDomainToSession"}, - {0x00000002, &Controller::DuplicateSession, "DuplicateSession"}, - {0x00000003, &Controller::QueryPointerBufferSize, "QueryPointerBufferSize"}, - {0x00000004, &Controller::DuplicateSessionEx, "DuplicateSessionEx"}, + {0, &Controller::ConvertCurrentObjectToDomain, "ConvertCurrentObjectToDomain"}, + {1, nullptr, "CopyFromCurrentDomain"}, + {2, &Controller::CloneCurrentObject, "CloneCurrentObject"}, + {3, &Controller::QueryPointerBufferSize, "QueryPointerBufferSize"}, + {4, &Controller::CloneCurrentObjectEx, "CloneCurrentObjectEx"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/sm/controller.h b/src/core/hle/service/sm/controller.h index dc66c9e37..180c6da50 100644 --- a/src/core/hle/service/sm/controller.h +++ b/src/core/hle/service/sm/controller.h @@ -14,9 +14,9 @@ public: ~Controller() override; private: - void ConvertSessionToDomain(Kernel::HLERequestContext& ctx); - void DuplicateSession(Kernel::HLERequestContext& ctx); - void DuplicateSessionEx(Kernel::HLERequestContext& ctx); + void ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx); + void CloneCurrentObject(Kernel::HLERequestContext& ctx); + void CloneCurrentObjectEx(Kernel::HLERequestContext& ctx); void QueryPointerBufferSize(Kernel::HLERequestContext& ctx); }; diff --git a/src/core/hle/service/sockets/nsd.cpp b/src/core/hle/service/sockets/nsd.cpp index dc70fd6fe..40d781124 100644 --- a/src/core/hle/service/sockets/nsd.cpp +++ b/src/core/hle/service/sockets/nsd.cpp @@ -14,6 +14,7 @@ NSD::NSD(const char* name) : ServiceFramework(name) { {12, nullptr, "GetDeviceId"}, {13, nullptr, "DeleteSettings"}, {14, nullptr, "ImportSettings"}, + {15, nullptr, "SetChangeEnvironmentIdentifierDisabled"}, {20, nullptr, "Resolve"}, {21, nullptr, "ResolveEx"}, {30, nullptr, "GetNasServiceSetting"}, @@ -28,6 +29,11 @@ NSD::NSD(const char* name) : ServiceFramework(name) { {60, nullptr, "ReadSaveDataFromFsForTest"}, {61, nullptr, "WriteSaveDataToFsForTest"}, {62, nullptr, "DeleteSaveDataOfFsForTest"}, + {63, nullptr, "IsChangeEnvironmentIdentifierDisabled"}, + {64, nullptr, "SetWithoutDomainExchangeFqdns"}, + {100, nullptr, "GetApplicationServerEnvironmentType"}, + {101, nullptr, "SetApplicationServerEnvironmentType"}, + {102, nullptr, "DeleteApplicationServerEnvironmentType"}, }; // clang-format on diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp index 852e71e4b..e3017451f 100644 --- a/src/core/hle/service/sockets/sfdnsres.cpp +++ b/src/core/hle/service/sockets/sfdnsres.cpp @@ -7,7 +7,7 @@ namespace Service::Sockets { -void SFDNSRES::GetAddrInfo(Kernel::HLERequestContext& ctx) { +void SFDNSRES::GetAddrInfoRequest(Kernel::HLERequestContext& ctx) { struct Parameters { u8 use_nsd_resolve; u32 unknown; @@ -29,15 +29,20 @@ SFDNSRES::SFDNSRES() : ServiceFramework("sfdnsres") { static const FunctionInfo functions[] = { {0, nullptr, "SetDnsAddressesPrivate"}, {1, nullptr, "GetDnsAddressPrivate"}, - {2, nullptr, "GetHostByName"}, - {3, nullptr, "GetHostByAddr"}, - {4, nullptr, "GetHostStringError"}, - {5, nullptr, "GetGaiStringError"}, - {6, &SFDNSRES::GetAddrInfo, "GetAddrInfo"}, - {7, nullptr, "GetNameInfo"}, - {8, nullptr, "RequestCancelHandle"}, - {9, nullptr, "CancelSocketCall"}, - {11, nullptr, "ClearDnsIpServerAddressArray"}, + {2, nullptr, "GetHostByNameRequest"}, + {3, nullptr, "GetHostByAddrRequest"}, + {4, nullptr, "GetHostStringErrorRequest"}, + {5, nullptr, "GetGaiStringErrorRequest"}, + {6, &SFDNSRES::GetAddrInfoRequest, "GetAddrInfoRequest"}, + {7, nullptr, "GetNameInfoRequest"}, + {8, nullptr, "RequestCancelHandleRequest"}, + {9, nullptr, "CancelRequest"}, + {10, nullptr, "GetHostByNameRequestWithOptions"}, + {11, nullptr, "GetHostByAddrRequestWithOptions"}, + {12, nullptr, "GetAddrInfoRequestWithOptions"}, + {13, nullptr, "GetNameInfoRequestWithOptions"}, + {14, nullptr, "ResolverSetOptionRequest"}, + {15, nullptr, "ResolverGetOptionRequest"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/sockets/sfdnsres.h b/src/core/hle/service/sockets/sfdnsres.h index eda432903..acd3647bb 100644 --- a/src/core/hle/service/sockets/sfdnsres.h +++ b/src/core/hle/service/sockets/sfdnsres.h @@ -15,7 +15,7 @@ public: ~SFDNSRES() override; private: - void GetAddrInfo(Kernel::HLERequestContext& ctx); + void GetAddrInfoRequest(Kernel::HLERequestContext& ctx); }; } // namespace Service::Sockets diff --git a/src/core/hle/service/spl/spl.cpp b/src/core/hle/service/spl/spl.cpp index 70cb41905..773551464 100644 --- a/src/core/hle/service/spl/spl.cpp +++ b/src/core/hle/service/spl/spl.cpp @@ -9,35 +9,36 @@ namespace Service::SPL { SPL::SPL(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "spl:") { static const FunctionInfo functions[] = { {0, nullptr, "GetConfig"}, - {1, nullptr, "UserExpMod"}, + {1, nullptr, "ModularExponentiate"}, {2, nullptr, "GenerateAesKek"}, {3, nullptr, "LoadAesKey"}, {4, nullptr, "GenerateAesKey"}, {5, nullptr, "SetConfig"}, {7, &SPL::GetRandomBytes, "GetRandomBytes"}, - {9, nullptr, "LoadSecureExpModKey"}, - {10, nullptr, "SecureExpMod"}, + {9, nullptr, "ImportLotusKey"}, + {10, nullptr, "DecryptLotusMessage"}, {11, nullptr, "IsDevelopment"}, {12, nullptr, "GenerateSpecificAesKey"}, - {13, nullptr, "DecryptPrivk"}, + {13, nullptr, "DecryptDeviceUniqueData"}, {14, nullptr, "DecryptAesKey"}, - {15, nullptr, "DecryptAesCtr"}, + {15, nullptr, "CryptAesCtr"}, {16, nullptr, "ComputeCmac"}, - {17, nullptr, "LoadRsaOaepKey"}, - {18, nullptr, "UnwrapRsaOaepWrappedTitleKey"}, + {17, nullptr, "ImportEsKey"}, + {18, nullptr, "UnwrapTitleKey"}, {19, nullptr, "LoadTitleKey"}, - {20, nullptr, "UnwrapAesWrappedTitleKey"}, - {21, nullptr, "LockAesEngine"}, - {22, nullptr, "UnlockAesEngine"}, - {23, nullptr, "GetSplWaitEvent"}, - {24, nullptr, "SetSharedData"}, - {25, nullptr, "GetSharedData"}, - {26, nullptr, "ImportSslRsaKey"}, - {27, nullptr, "SecureExpModWithSslKey"}, - {28, nullptr, "ImportEsRsaKey"}, - {29, nullptr, "SecureExpModWithEsKey"}, - {30, nullptr, "EncryptManuRsaKeyForImport"}, - {31, nullptr, "GetPackage2Hash"}, + {20, nullptr, "PrepareEsCommonKey"}, + {21, nullptr, "AllocateAesKeyslot"}, + {22, nullptr, "DeallocateAesKeySlot"}, + {23, nullptr, "GetAesKeyslotAvailableEvent"}, + {24, nullptr, "SetBootReason"}, + {25, nullptr, "GetBootReason"}, + {26, nullptr, "DecryptAndStoreSslClientCertKey"}, + {27, nullptr, "ModularExponentiateWithSslClientCertKey"}, + {28, nullptr, "DecryptAndStoreDrmDeviceCertKey"}, + {29, nullptr, "ModularExponentiateWithDrmDeviceCertKey"}, + {30, nullptr, "ReencryptDeviceUniqueData "}, + {31, nullptr, "PrepareEsArchiveKey"}, // This is also GetPackage2Hash? + {32, nullptr, "LoadPreparedAesKey"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 4cf58a61a..13e4b3818 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -90,6 +90,13 @@ public: : ServiceFramework("ISteadyClock"), clock_core{clock_core}, system{system} { static const FunctionInfo functions[] = { {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"}, + {2, nullptr, "GetTestOffset"}, + {3, nullptr, "SetTestOffset"}, + {100, nullptr, "GetRtcValue"}, + {101, nullptr, "IsRtcResetDetected"}, + {102, nullptr, "GetSetupResultValue"}, + {200, nullptr, "GetInternalOffset"}, + {201, nullptr, "SetInternalOffset"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp index 58a9845fc..d033f8603 100644 --- a/src/core/hle/service/usb/usb.cpp +++ b/src/core/hle/service/usb/usb.cpp @@ -20,7 +20,7 @@ public: static const FunctionInfo functions[] = { {0, nullptr, "GetDsEndpoint"}, {1, nullptr, "GetSetupEvent"}, - {2, nullptr, "Unknown"}, + {2, nullptr, "Unknown2"}, {3, nullptr, "EnableInterface"}, {4, nullptr, "DisableInterface"}, {5, nullptr, "CtrlInPostBufferAsync"}, @@ -55,6 +55,7 @@ public: {9, nullptr, "SetBinaryObjectStore"}, {10, nullptr, "Enable"}, {11, nullptr, "Disable"}, + {12, nullptr, "Unknown12"}, }; // clang-format on @@ -69,13 +70,13 @@ public: static const FunctionInfo functions[] = { {0, nullptr, "Open"}, {1, nullptr, "Close"}, - {2, nullptr, "Unknown1"}, + {2, nullptr, "Unknown2"}, {3, nullptr, "Populate"}, {4, nullptr, "PostBufferAsync"}, {5, nullptr, "GetXferReport"}, {6, nullptr, "PostBufferMultiAsync"}, - {7, nullptr, "Unknown3"}, - {8, nullptr, "Unknown4"}, + {7, nullptr, "Unknown7"}, + {8, nullptr, "Unknown8"}, }; // clang-format on @@ -88,13 +89,13 @@ public: explicit IClientIfSession() : ServiceFramework{"IClientIfSession"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "Unknown1"}, + {0, nullptr, "Unknown0"}, {1, nullptr, "SetInterface"}, {2, nullptr, "GetInterface"}, {3, nullptr, "GetAlternateInterface"}, {4, nullptr, "GetCurrentFrame"}, {5, nullptr, "CtrlXferAsync"}, - {6, nullptr, "Unknown2"}, + {6, nullptr, "Unknown6"}, {7, nullptr, "GetCtrlXferReport"}, {8, nullptr, "ResetDevice"}, {9, nullptr, "OpenUsbEp"}, @@ -118,7 +119,7 @@ public: {5, nullptr, "DestroyInterfaceAvailableEvent"}, {6, nullptr, "GetInterfaceStateChangeEvent"}, {7, nullptr, "AcquireUsbIf"}, - {8, nullptr, "Unknown1"}, + {8, nullptr, "Unknown8"}, }; // clang-format on @@ -179,8 +180,8 @@ public: {4, nullptr, "GetFwRevision"}, {5, nullptr, "GetManufacturerId"}, {6, nullptr, "GetDeviceId"}, - {7, nullptr, "Unknown1"}, - {8, nullptr, "Unknown2"}, + {7, nullptr, "Unknown7"}, + {8, nullptr, "Unknown8"}, }; // clang-format on @@ -215,12 +216,12 @@ public: explicit USB_PM() : ServiceFramework{"usb:pm"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "Unknown1"}, - {1, nullptr, "Unknown2"}, - {2, nullptr, "Unknown3"}, - {3, nullptr, "Unknown4"}, - {4, nullptr, "Unknown5"}, - {5, nullptr, "Unknown6"}, + {0, nullptr, "Unknown0"}, + {1, nullptr, "Unknown1"}, + {2, nullptr, "Unknown2"}, + {3, nullptr, "Unknown3"}, + {4, nullptr, "Unknown4"}, + {5, nullptr, "Unknown5"}, }; // clang-format on diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 552a5e4ef..ea7b4ae13 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -700,6 +700,7 @@ public: {3215, nullptr, "SetDisplayGamma"}, {3216, nullptr, "GetDisplayCmuLuma"}, {3217, nullptr, "SetDisplayCmuLuma"}, + {6013, nullptr, "GetLayerPresentationSubmissionTimestamps"}, {8225, nullptr, "GetSharedBufferMemoryHandleId"}, {8250, nullptr, "OpenSharedLayer"}, {8251, nullptr, "CloseSharedLayer"}, @@ -785,6 +786,7 @@ public: {2300, nullptr, "AcquireLayerTexturePresentingEvent"}, {2301, nullptr, "ReleaseLayerTexturePresentingEvent"}, {2302, nullptr, "GetDisplayHotplugEvent"}, + {2303, nullptr, "GetDisplayModeChangedEvent"}, {2402, nullptr, "GetDisplayHotplugState"}, {2501, nullptr, "GetCompositorErrorInfo"}, {2601, nullptr, "GetDisplayErrorEvent"}, diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp index 9d5ceb608..6b7329345 100644 --- a/src/core/hle/service/vi/vi_u.cpp +++ b/src/core/hle/service/vi/vi_u.cpp @@ -12,6 +12,7 @@ VI_U::VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) : ServiceFramework{"vi:u"}, nv_flinger{std::move(nv_flinger)} { static const FunctionInfo functions[] = { {0, &VI_U::GetDisplayService, "GetDisplayService"}, + {1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/wlan/wlan.cpp b/src/core/hle/service/wlan/wlan.cpp index 2654594c1..0260d7dcf 100644 --- a/src/core/hle/service/wlan/wlan.cpp +++ b/src/core/hle/service/wlan/wlan.cpp @@ -15,34 +15,37 @@ public: explicit WLANInfra() : ServiceFramework{"wlan:inf"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "Unknown1"}, - {1, nullptr, "Unknown2"}, + {0, nullptr, "OpenMode"}, + {1, nullptr, "CloseMode"}, {2, nullptr, "GetMacAddress"}, {3, nullptr, "StartScan"}, {4, nullptr, "StopScan"}, {5, nullptr, "Connect"}, {6, nullptr, "CancelConnect"}, {7, nullptr, "Disconnect"}, - {8, nullptr, "Unknown3"}, - {9, nullptr, "Unknown4"}, + {8, nullptr, "GetConnectionEvent"}, + {9, nullptr, "GetConnectionStatus"}, {10, nullptr, "GetState"}, {11, nullptr, "GetScanResult"}, {12, nullptr, "GetRssi"}, {13, nullptr, "ChangeRxAntenna"}, - {14, nullptr, "Unknown5"}, - {15, nullptr, "Unknown6"}, + {14, nullptr, "GetFwVersion"}, + {15, nullptr, "RequestSleep"}, {16, nullptr, "RequestWakeUp"}, {17, nullptr, "RequestIfUpDown"}, - {18, nullptr, "Unknown7"}, - {19, nullptr, "Unknown8"}, - {20, nullptr, "Unknown9"}, - {21, nullptr, "Unknown10"}, - {22, nullptr, "Unknown11"}, - {23, nullptr, "Unknown12"}, - {24, nullptr, "Unknown13"}, - {25, nullptr, "Unknown14"}, - {26, nullptr, "Unknown15"}, - {27, nullptr, "Unknown16"}, + {18, nullptr, "Unknown18"}, + {19, nullptr, "Unknown19"}, + {20, nullptr, "Unknown20"}, + {21, nullptr, "Unknown21"}, + {22, nullptr, "Unknown22"}, + {23, nullptr, "Unknown23"}, + {24, nullptr, "Unknown24"}, + {25, nullptr, "Unknown25"}, + {26, nullptr, "Unknown26"}, + {27, nullptr, "Unknown27"}, + {28, nullptr, "Unknown28"}, + {29, nullptr, "Unknown29"}, + {30, nullptr, "Unknown30"}, }; // clang-format on @@ -55,12 +58,12 @@ public: explicit WLANLocal() : ServiceFramework{"wlan:lcl"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "Unknown1"}, - {1, nullptr, "Unknown2"}, - {2, nullptr, "Unknown3"}, - {3, nullptr, "Unknown4"}, - {4, nullptr, "Unknown5"}, - {5, nullptr, "Unknown6"}, + {0, nullptr, "Unknown0"}, + {1, nullptr, "Unknown1"}, + {2, nullptr, "Unknown2"}, + {3, nullptr, "Unknown3"}, + {4, nullptr, "Unknown4"}, + {5, nullptr, "Unknown5"}, {6, nullptr, "GetMacAddress"}, {7, nullptr, "CreateBss"}, {8, nullptr, "DestroyBss"}, @@ -72,38 +75,42 @@ public: {14, nullptr, "CancelJoin"}, {15, nullptr, "Disconnect"}, {16, nullptr, "SetBeaconLostCount"}, - {17, nullptr, "Unknown7"}, - {18, nullptr, "Unknown8"}, - {19, nullptr, "Unknown9"}, + {17, nullptr, "Unknown17"}, + {18, nullptr, "Unknown18"}, + {19, nullptr, "Unknown19"}, {20, nullptr, "GetBssIndicationEvent"}, {21, nullptr, "GetBssIndicationInfo"}, {22, nullptr, "GetState"}, {23, nullptr, "GetAllowedChannels"}, {24, nullptr, "AddIe"}, {25, nullptr, "DeleteIe"}, - {26, nullptr, "Unknown10"}, - {27, nullptr, "Unknown11"}, + {26, nullptr, "Unknown26"}, + {27, nullptr, "Unknown27"}, {28, nullptr, "CreateRxEntry"}, {29, nullptr, "DeleteRxEntry"}, - {30, nullptr, "Unknown12"}, - {31, nullptr, "Unknown13"}, + {30, nullptr, "Unknown30"}, + {31, nullptr, "Unknown31"}, {32, nullptr, "AddMatchingDataToRxEntry"}, {33, nullptr, "RemoveMatchingDataFromRxEntry"}, {34, nullptr, "GetScanResult"}, - {35, nullptr, "Unknown14"}, + {35, nullptr, "Unknown35"}, {36, nullptr, "SetActionFrameWithBeacon"}, {37, nullptr, "CancelActionFrameWithBeacon"}, {38, nullptr, "CreateRxEntryForActionFrame"}, {39, nullptr, "DeleteRxEntryForActionFrame"}, - {40, nullptr, "Unknown15"}, - {41, nullptr, "Unknown16"}, + {40, nullptr, "Unknown40"}, + {41, nullptr, "Unknown41"}, {42, nullptr, "CancelGetActionFrame"}, {43, nullptr, "GetRssi"}, - {44, nullptr, "Unknown17"}, - {45, nullptr, "Unknown18"}, - {46, nullptr, "Unknown19"}, - {47, nullptr, "Unknown20"}, - {48, nullptr, "Unknown21"}, + {44, nullptr, "Unknown44"}, + {45, nullptr, "Unknown45"}, + {46, nullptr, "Unknown46"}, + {47, nullptr, "Unknown47"}, + {48, nullptr, "Unknown48"}, + {49, nullptr, "Unknown49"}, + {50, nullptr, "Unknown50"}, + {51, nullptr, "Unknown51"}, + {52, nullptr, "Unknown52"}, }; // clang-format on @@ -142,18 +149,19 @@ public: explicit WLANSocketManager() : ServiceFramework{"wlan:soc"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "Unknown1"}, - {1, nullptr, "Unknown2"}, - {2, nullptr, "Unknown3"}, - {3, nullptr, "Unknown4"}, - {4, nullptr, "Unknown5"}, - {5, nullptr, "Unknown6"}, + {0, nullptr, "Unknown0"}, + {1, nullptr, "Unknown1"}, + {2, nullptr, "Unknown2"}, + {3, nullptr, "Unknown3"}, + {4, nullptr, "Unknown4"}, + {5, nullptr, "Unknown5"}, {6, nullptr, "GetMacAddress"}, {7, nullptr, "SwitchTsfTimerFunction"}, - {8, nullptr, "Unknown7"}, - {9, nullptr, "Unknown8"}, - {10, nullptr, "Unknown9"}, - {11, nullptr, "Unknown10"}, + {8, nullptr, "Unknown8"}, + {9, nullptr, "Unknown9"}, + {10, nullptr, "Unknown10"}, + {11, nullptr, "Unknown11"}, + {12, nullptr, "Unknown12"}, }; // clang-format on diff --git a/src/core/settings.cpp b/src/core/settings.cpp index d3886c4ec..64a3c69d3 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -184,4 +184,9 @@ void RestoreGlobalState() { values.sound_index.SetGlobal(true); } +void Sanitize() { + values.use_asynchronous_gpu_emulation.SetValue( + values.use_asynchronous_gpu_emulation.GetValue() || values.use_multi_core.GetValue()); +} + } // namespace Settings diff --git a/src/core/settings.h b/src/core/settings.h index 850ca4072..a64debd25 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -346,31 +346,6 @@ struct TouchscreenInput { u32 rotation_angle; }; -enum class NANDTotalSize : u64 { - S29_1GB = 0x747C00000ULL, -}; - -enum class NANDUserSize : u64 { - S26GB = 0x680000000ULL, -}; - -enum class NANDSystemSize : u64 { - S2_5GB = 0xA0000000, -}; - -enum class SDMCSize : u64 { - S1GB = 0x40000000, - S2GB = 0x80000000, - S4GB = 0x100000000ULL, - S8GB = 0x200000000ULL, - S16GB = 0x400000000ULL, - S32GB = 0x800000000ULL, - S64GB = 0x1000000000ULL, - S128GB = 0x2000000000ULL, - S256GB = 0x4000000000ULL, - S1TB = 0x10000000000ULL, -}; - enum class RendererBackend { OpenGL = 0, Vulkan = 1, @@ -382,6 +357,11 @@ enum class GPUAccuracy : u32 { Extreme = 2, }; +enum class CPUAccuracy { + Accurate = 0, + DebugMode = 1, +}; + extern bool configuring_global; template <typename Type> @@ -427,6 +407,18 @@ struct Values { // Core Setting<bool> use_multi_core; + // Cpu + CPUAccuracy cpu_accuracy; + + bool cpuopt_page_tables; + bool cpuopt_block_linking; + bool cpuopt_return_stack_buffer; + bool cpuopt_fast_dispatcher; + bool cpuopt_context_elimination; + bool cpuopt_const_prop; + bool cpuopt_misc_ir; + bool cpuopt_reduce_misalign_checks; + // Renderer Setting<RendererBackend> renderer_backend; bool renderer_debug; @@ -491,10 +483,6 @@ struct Values { bool gamecard_inserted; bool gamecard_current_game; std::string gamecard_path; - NANDTotalSize nand_total_size; - NANDSystemSize nand_system_size; - NANDUserSize nand_user_size; - SDMCSize sdmc_size; // Debugging bool record_frame_times; @@ -505,7 +493,6 @@ struct Values { bool dump_nso; bool reporting_services; bool quest_flag; - bool disable_cpu_opt; bool disable_macro_jit; // Misceallaneous @@ -539,4 +526,7 @@ void LogSettings(); // Restore the global state of all applicable settings in the Values struct void RestoreGlobalState(); +// Fixes settings that are known to cause issues with the emulator +void Sanitize(); + } // namespace Settings diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 3bd76dd23..317c25bad 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -30,7 +30,8 @@ if(SDL2_FOUND) target_compile_definitions(input_common PRIVATE HAVE_SDL2) endif() -target_link_libraries(input_common PUBLIC ${LIBUSB_LIBRARIES}) +target_include_directories(input_common SYSTEM PRIVATE ${LIBUSB_INCLUDE_DIR}) +target_link_libraries(input_common PRIVATE ${LIBUSB_LIBRARIES}) create_target_directory_groups(input_common) target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost) diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp index 6d9f4d9eb..898a278a9 100644 --- a/src/input_common/gcadapter/gc_adapter.cpp +++ b/src/input_common/gcadapter/gc_adapter.cpp @@ -4,6 +4,7 @@ #include <chrono> #include <thread> +#include <libusb.h> #include "common/logging/log.h" #include "input_common/gcadapter/gc_adapter.h" @@ -24,6 +25,7 @@ Adapter::Adapter() { LOG_INFO(Input, "GC Adapter Initialization started"); current_status = NO_ADAPTER_DETECTED; + get_origin.fill(true); const int init_res = libusb_init(&libusb_ctx); if (init_res == LIBUSB_SUCCESS) { @@ -33,15 +35,10 @@ Adapter::Adapter() { } } -GCPadStatus Adapter::GetPadStatus(int port, const std::array<u8, 37>& adapter_payload) { +GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload) { GCPadStatus pad = {}; - bool get_origin = false; ControllerTypes type = ControllerTypes(adapter_payload[1 + (9 * port)] >> 4); - if (type != ControllerTypes::None) { - get_origin = true; - } - adapter_controllers_status[port] = type; static constexpr std::array<PadButton, 8> b1_buttons{ @@ -57,6 +54,11 @@ GCPadStatus Adapter::GetPadStatus(int port, const std::array<u8, 37>& adapter_pa PadButton::PAD_TRIGGER_L, }; + if (adapter_controllers_status[port] == ControllerTypes::None && !get_origin[port]) { + // Controller may have been disconnected, recalibrate if reconnected. + get_origin[port] = true; + } + if (adapter_controllers_status[port] != ControllerTypes::None) { const u8 b1 = adapter_payload[1 + (9 * port) + 1]; const u8 b2 = adapter_payload[1 + (9 * port) + 2]; @@ -73,16 +75,22 @@ GCPadStatus Adapter::GetPadStatus(int port, const std::array<u8, 37>& adapter_pa } } - if (get_origin) { - pad.button |= PAD_GET_ORIGIN; - } - pad.stick_x = adapter_payload[1 + (9 * port) + 3]; pad.stick_y = adapter_payload[1 + (9 * port) + 4]; pad.substick_x = adapter_payload[1 + (9 * port) + 5]; pad.substick_y = adapter_payload[1 + (9 * port) + 6]; pad.trigger_left = adapter_payload[1 + (9 * port) + 7]; pad.trigger_right = adapter_payload[1 + (9 * port) + 8]; + + if (get_origin[port]) { + origin_status[port].stick_x = pad.stick_x; + origin_status[port].stick_y = pad.stick_y; + origin_status[port].substick_x = pad.substick_x; + origin_status[port].substick_y = pad.substick_y; + origin_status[port].trigger_left = pad.trigger_left; + origin_status[port].trigger_right = pad.trigger_right; + get_origin[port] = false; + } } return pad; } @@ -131,31 +139,31 @@ void Adapter::Read() { for (std::size_t port = 0; port < pads.size(); ++port) { pads[port] = GetPadStatus(port, adapter_payload_copy); if (DeviceConnected(port) && configuring) { - if (pads[port].button != PAD_GET_ORIGIN) { + if (pads[port].button != 0) { pad_queue[port].Push(pads[port]); } // Accounting for a threshold here because of some controller variance - if (pads[port].stick_x > pads[port].MAIN_STICK_CENTER_X + pads[port].THRESHOLD || - pads[port].stick_x < pads[port].MAIN_STICK_CENTER_X - pads[port].THRESHOLD) { + if (pads[port].stick_x > origin_status[port].stick_x + pads[port].THRESHOLD || + pads[port].stick_x < origin_status[port].stick_x - pads[port].THRESHOLD) { pads[port].axis = GCAdapter::PadAxes::StickX; pads[port].axis_value = pads[port].stick_x; pad_queue[port].Push(pads[port]); } - if (pads[port].stick_y > pads[port].MAIN_STICK_CENTER_Y + pads[port].THRESHOLD || - pads[port].stick_y < pads[port].MAIN_STICK_CENTER_Y - pads[port].THRESHOLD) { + if (pads[port].stick_y > origin_status[port].stick_y + pads[port].THRESHOLD || + pads[port].stick_y < origin_status[port].stick_y - pads[port].THRESHOLD) { pads[port].axis = GCAdapter::PadAxes::StickY; pads[port].axis_value = pads[port].stick_y; pad_queue[port].Push(pads[port]); } - if (pads[port].substick_x > pads[port].C_STICK_CENTER_X + pads[port].THRESHOLD || - pads[port].substick_x < pads[port].C_STICK_CENTER_X - pads[port].THRESHOLD) { + if (pads[port].substick_x > origin_status[port].substick_x + pads[port].THRESHOLD || + pads[port].substick_x < origin_status[port].substick_x - pads[port].THRESHOLD) { pads[port].axis = GCAdapter::PadAxes::SubstickX; pads[port].axis_value = pads[port].substick_x; pad_queue[port].Push(pads[port]); } - if (pads[port].substick_y > pads[port].C_STICK_CENTER_Y + pads[port].THRESHOLD || - pads[port].substick_y < pads[port].C_STICK_CENTER_Y - pads[port].THRESHOLD) { + if (pads[port].substick_y > origin_status[port].substick_y + pads[port].THRESHOLD || + pads[port].substick_y < origin_status[port].substick_y - pads[port].THRESHOLD) { pads[port].axis = GCAdapter::PadAxes::SubstickY; pads[port].axis_value = pads[port].substick_y; pad_queue[port].Push(pads[port]); @@ -198,7 +206,7 @@ void Adapter::StartScanThread() { } detect_thread_running = true; - detect_thread = std::thread([=] { ScanThreadFunc(); }); + detect_thread = std::thread(&Adapter::ScanThreadFunc, this); } void Adapter::StopScanThread() { @@ -227,7 +235,7 @@ void Adapter::Setup() { } if (devices != nullptr) { - for (std::size_t index = 0; index < device_count; ++index) { + for (std::size_t index = 0; index < static_cast<std::size_t>(device_count); ++index) { if (CheckDeviceAccess(devices[index])) { // GC Adapter found and accessible, registering it GetGCEndpoint(devices[index]); @@ -236,6 +244,9 @@ void Adapter::Setup() { } libusb_free_device_list(devices, 1); } + // Break out of the ScanThreadFunc() loop that is constantly looking for the device + // Assumes user has GC adapter plugged in before launch to use the adapter + detect_thread_running = false; } bool Adapter::CheckDeviceAccess(libusb_device* device) { @@ -344,6 +355,7 @@ void Adapter::Reset() { adapter_input_thread.join(); adapter_controllers_status.fill(ControllerTypes::None); + get_origin.fill(true); current_status = NO_ADAPTER_DETECTED; if (usb_adapter_handle) { @@ -357,15 +369,16 @@ void Adapter::Reset() { } } -bool Adapter::DeviceConnected(int port) { +bool Adapter::DeviceConnected(std::size_t port) { return adapter_controllers_status[port] != ControllerTypes::None; } -void Adapter::ResetDeviceType(int port) { +void Adapter::ResetDeviceType(std::size_t port) { adapter_controllers_status[port] = ControllerTypes::None; } void Adapter::BeginConfiguration() { + get_origin.fill(true); for (auto& pq : pad_queue) { pq.Clear(); } @@ -395,4 +408,25 @@ const std::array<GCState, 4>& Adapter::GetPadState() const { return state; } +int Adapter::GetOriginValue(int port, int axis) const { + const auto& status = origin_status[port]; + + switch (static_cast<PadAxes>(axis)) { + case PadAxes::StickX: + return status.stick_x; + case PadAxes::StickY: + return status.stick_y; + case PadAxes::SubstickX: + return status.substick_x; + case PadAxes::SubstickY: + return status.substick_y; + case PadAxes::TriggerLeft: + return status.trigger_left; + case PadAxes::TriggerRight: + return status.trigger_right; + default: + return 0; + } +} + } // namespace GCAdapter diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h index b1c2a1958..3586c8bda 100644 --- a/src/input_common/gcadapter/gc_adapter.h +++ b/src/input_common/gcadapter/gc_adapter.h @@ -8,17 +8,14 @@ #include <mutex> #include <thread> #include <unordered_map> -#include <libusb.h> #include "common/common_types.h" #include "common/threadsafe_queue.h" -namespace GCAdapter { +struct libusb_context; +struct libusb_device; +struct libusb_device_handle; -enum { - PAD_USE_ORIGIN = 0x0080, - PAD_GET_ORIGIN = 0x2000, - PAD_ERR_STATUS = 0x8000, -}; +namespace GCAdapter { enum class PadButton { PAD_BUTTON_LEFT = 0x0001, @@ -97,14 +94,19 @@ public: void BeginConfiguration(); void EndConfiguration(); + /// Returns true if there is a device connected to port + bool DeviceConnected(std::size_t port); + std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue(); const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const; std::array<GCState, 4>& GetPadState(); const std::array<GCState, 4>& GetPadState() const; + int GetOriginValue(int port, int axis) const; + private: - GCPadStatus GetPadStatus(int port, const std::array<u8, 37>& adapter_payload); + GCPadStatus GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload); void PadToState(const GCPadStatus& pad, GCState& state); @@ -116,11 +118,8 @@ private: /// Stop scanning for the adapter void StopScanThread(); - /// Returns true if there is a device connected to port - bool DeviceConnected(int port); - /// Resets status of device connected to port - void ResetDeviceType(int port); + void ResetDeviceType(std::size_t port); /// Returns true if we successfully gain access to GC Adapter bool CheckDeviceAccess(libusb_device* device); @@ -156,6 +155,8 @@ private: std::array<Common::SPSCQueue<GCPadStatus>, 4> pad_queue; std::array<GCState, 4> state; + std::array<bool, 4> get_origin; + std::array<GCPadStatus, 4> origin_status; }; } // namespace GCAdapter diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp index 385ce8430..96e22d3ad 100644 --- a/src/input_common/gcadapter/gc_poller.cpp +++ b/src/input_common/gcadapter/gc_poller.cpp @@ -6,6 +6,7 @@ #include <list> #include <mutex> #include <utility> +#include "common/assert.h" #include "common/threadsafe_queue.h" #include "input_common/gcadapter/gc_adapter.h" #include "input_common/gcadapter/gc_poller.h" @@ -20,7 +21,10 @@ public: ~GCButton() override; bool GetStatus() const override { - return gcadapter->GetPadState()[port].buttons.at(button); + if (gcadapter->DeviceConnected(port)) { + return gcadapter->GetPadState()[port].buttons.at(button); + } + return false; } private: @@ -34,22 +38,20 @@ public: explicit GCAxisButton(int port_, int axis_, float threshold_, bool trigger_if_greater_, GCAdapter::Adapter* adapter) : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_), - gcadapter(adapter) { - // L/R triggers range is only in positive direction beginning near 0 - // 0.0 threshold equates to near half trigger press, but threshold accounts for variability. - if (axis > 3) { - threshold *= -0.5; - } - } + gcadapter(adapter), origin_value(adapter->GetOriginValue(port_, axis_)) {} bool GetStatus() const override { - const float axis_value = (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 128.0f; - if (trigger_if_greater) { - // TODO: Might be worthwile to set a slider for the trigger threshold. It is currently - // always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick - return axis_value > threshold; + if (gcadapter->DeviceConnected(port)) { + const float current_axis_value = gcadapter->GetPadState()[port].axes.at(axis); + const float axis_value = (current_axis_value - origin_value) / 128.0f; + if (trigger_if_greater) { + // TODO: Might be worthwile to set a slider for the trigger threshold. It is + // currently always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick + return axis_value > threshold; + } + return axis_value < -threshold; } - return axis_value < -threshold; + return false; } private: @@ -58,6 +60,7 @@ private: float threshold; bool trigger_if_greater; GCAdapter::Adapter* gcadapter; + const float origin_value; }; GCButtonFactory::GCButtonFactory(std::shared_ptr<GCAdapter::Adapter> adapter_) @@ -94,9 +97,12 @@ std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::Param return std::make_unique<GCAxisButton>(port, axis, threshold, trigger_if_greater, adapter.get()); } + + UNREACHABLE(); + return nullptr; } -Common::ParamPackage GCButtonFactory::GetNextInput() { +Common::ParamPackage GCButtonFactory::GetNextInput() const { Common::ParamPackage params; GCAdapter::GCPadStatus pad; auto& queue = adapter->GetPadQueue(); @@ -144,14 +150,20 @@ void GCButtonFactory::EndConfiguration() { class GCAnalog final : public Input::AnalogDevice { public: GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter) - : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter) {} + : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter), + origin_value_x(adapter->GetOriginValue(port_, axis_x_)), + origin_value_y(adapter->GetOriginValue(port_, axis_y_)) {} float GetAxis(int axis) const { - std::lock_guard lock{mutex}; - // division is not by a perfect 128 to account for some variance in center location - // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range - // [20-230] - return (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 95.0f; + if (gcadapter->DeviceConnected(port)) { + std::lock_guard lock{mutex}; + const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y; + // division is not by a perfect 128 to account for some variance in center location + // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range + // [20-230] + return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / 95.0f; + } + return 0.0f; } std::pair<float, float> GetAnalog(int axis_x, int axis_y) const { @@ -201,8 +213,10 @@ private: const int axis_x; const int axis_y; const float deadzone; - mutable std::mutex mutex; GCAdapter::Adapter* gcadapter; + const float origin_value_x; + const float origin_value_y; + mutable std::mutex mutex; }; /// An analog device factory that creates analog devices from GC Adapter @@ -249,7 +263,7 @@ Common::ParamPackage GCAnalogFactory::GetNextInput() { const u8 axis = static_cast<u8>(pad.axis); if (analog_x_axis == -1) { analog_x_axis = axis; - controller_number = port; + controller_number = static_cast<int>(port); } else if (analog_y_axis == -1 && analog_x_axis != axis && controller_number == port) { analog_y_axis = axis; } diff --git a/src/input_common/gcadapter/gc_poller.h b/src/input_common/gcadapter/gc_poller.h index e96af7d51..0527f328f 100644 --- a/src/input_common/gcadapter/gc_poller.h +++ b/src/input_common/gcadapter/gc_poller.h @@ -25,7 +25,7 @@ public: */ std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override; - Common::ParamPackage GetNextInput(); + Common::ParamPackage GetNextInput() const; /// For device input configuration/polling void BeginConfiguration(); diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index fd0af1019..b9d5d0ec3 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -4,7 +4,6 @@ #include <memory> #include <thread> -#include <libusb.h> #include "common/param_package.h" #include "input_common/analog_from_button.h" #include "input_common/gcadapter/gc_adapter.h" diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp index da5227058..e63c73c4f 100644 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/udp/client.cpp @@ -234,7 +234,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( std::function<void(Status)> status_callback, std::function<void(u16, u16, u16, u16)> data_callback) { - std::thread([=] { + std::thread([=, this] { constexpr u16 CALIBRATION_THRESHOLD = 100; u16 min_x{UINT16_MAX}; diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index 01d7df405..a2d3d7823 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp @@ -14,50 +14,45 @@ namespace Tegra::Engines { +using namespace Texture; + MaxwellDMA::MaxwellDMA(Core::System& system, MemoryManager& memory_manager) : system{system}, memory_manager{memory_manager} {} void MaxwellDMA::CallMethod(u32 method, u32 method_argument, bool is_last_call) { - ASSERT_MSG(method < Regs::NUM_REGS, - "Invalid MaxwellDMA register, increase the size of the Regs structure"); + ASSERT_MSG(method < NUM_REGS, "Invalid MaxwellDMA register"); regs.reg_array[method] = method_argument; -#define MAXWELLDMA_REG_INDEX(field_name) \ - (offsetof(Tegra::Engines::MaxwellDMA::Regs, field_name) / sizeof(u32)) - - switch (method) { - case MAXWELLDMA_REG_INDEX(exec): { - HandleCopy(); - break; - } + if (method == offsetof(Regs, launch_dma) / sizeof(u32)) { + Launch(); } - -#undef MAXWELLDMA_REG_INDEX } void MaxwellDMA::CallMultiMethod(u32 method, const u32* base_start, u32 amount, u32 methods_pending) { - for (std::size_t i = 0; i < amount; i++) { + for (size_t i = 0; i < amount; ++i) { CallMethod(method, base_start[i], methods_pending - static_cast<u32>(i) <= 1); } } -void MaxwellDMA::HandleCopy() { - LOG_TRACE(HW_GPU, "Requested a DMA copy"); - - const GPUVAddr source = regs.src_address.Address(); - const GPUVAddr dest = regs.dst_address.Address(); +void MaxwellDMA::Launch() { + LOG_TRACE(Render_OpenGL, "DMA copy 0x{:x} -> 0x{:x}", static_cast<GPUVAddr>(regs.offset_in), + static_cast<GPUVAddr>(regs.offset_out)); // TODO(Subv): Perform more research and implement all features of this engine. - ASSERT(regs.exec.enable_swizzle == 0); - ASSERT(regs.exec.query_mode == Regs::QueryMode::None); - ASSERT(regs.exec.query_intr == Regs::QueryIntr::None); - ASSERT(regs.exec.copy_mode == Regs::CopyMode::Unk2); - ASSERT(regs.dst_params.pos_x == 0); - ASSERT(regs.dst_params.pos_y == 0); - - if (!regs.exec.is_dst_linear && !regs.exec.is_src_linear) { + const LaunchDMA& launch = regs.launch_dma; + ASSERT(launch.remap_enable == 0); + ASSERT(launch.semaphore_type == LaunchDMA::SemaphoreType::NONE); + ASSERT(launch.interrupt_type == LaunchDMA::InterruptType::NONE); + ASSERT(launch.data_transfer_type == LaunchDMA::DataTransferType::NON_PIPELINED); + ASSERT(regs.dst_params.origin.x == 0); + ASSERT(regs.dst_params.origin.y == 0); + + const bool is_src_pitch = launch.src_memory_layout == LaunchDMA::MemoryLayout::PITCH; + const bool is_dst_pitch = launch.dst_memory_layout == LaunchDMA::MemoryLayout::PITCH; + + if (!is_src_pitch && !is_dst_pitch) { // If both the source and the destination are in block layout, assert. UNREACHABLE_MSG("Tiled->Tiled DMA transfers are not yet implemented"); return; @@ -66,144 +61,161 @@ void MaxwellDMA::HandleCopy() { // All copies here update the main memory, so mark all rasterizer states as invalid. system.GPU().Maxwell3D().OnMemoryWrite(); - if (regs.exec.is_dst_linear && regs.exec.is_src_linear) { - // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D - // buffer of length `x_count`, otherwise we copy a 2D image of dimensions (x_count, - // y_count). - if (!regs.exec.enable_2d) { - memory_manager.CopyBlock(dest, source, regs.x_count); - return; - } + if (is_src_pitch && is_dst_pitch) { + CopyPitchToPitch(); + } else { + ASSERT(launch.multi_line_enable == 1); - // If both the source and the destination are in linear layout, perform a line-by-line - // copy. We're going to take a subrect of size (x_count, y_count) from the source - // rectangle. There is no need to manually flush/invalidate the regions because - // CopyBlock does that for us. - for (u32 line = 0; line < regs.y_count; ++line) { - const GPUVAddr source_line = source + line * regs.src_pitch; - const GPUVAddr dest_line = dest + line * regs.dst_pitch; - memory_manager.CopyBlock(dest_line, source_line, regs.x_count); + if (!is_src_pitch && is_dst_pitch) { + CopyBlockLinearToPitch(); + } else { + CopyPitchToBlockLinear(); } - return; } +} - ASSERT(regs.exec.enable_2d == 1); - - if (regs.exec.is_dst_linear && !regs.exec.is_src_linear) { - - ASSERT(regs.src_params.BlockDepth() == 0); - // Optimized path for micro copies. - if (regs.dst_pitch * regs.y_count < Texture::GetGOBSize() && regs.dst_pitch <= 64) { - const u32 bytes_per_pixel = regs.dst_pitch / regs.x_count; - const std::size_t src_size = Texture::GetGOBSize(); - const std::size_t dst_size = regs.dst_pitch * regs.y_count; - u32 pos_x = regs.src_params.pos_x; - u32 pos_y = regs.src_params.pos_y; - const u64 offset = - Texture::GetGOBOffset(regs.src_params.size_x, regs.src_params.size_y, pos_x, pos_y, - regs.src_params.BlockDepth(), bytes_per_pixel); - const u32 x_in_gob = 64 / bytes_per_pixel; - pos_x = pos_x % x_in_gob; - pos_y = pos_y % 8; - - if (read_buffer.size() < src_size) { - read_buffer.resize(src_size); - } - - if (write_buffer.size() < dst_size) { - write_buffer.resize(dst_size); - } - - if (Settings::IsGPULevelExtreme()) { - memory_manager.ReadBlock(source + offset, read_buffer.data(), src_size); - memory_manager.ReadBlock(dest, write_buffer.data(), dst_size); - } else { - memory_manager.ReadBlockUnsafe(source + offset, read_buffer.data(), src_size); - memory_manager.ReadBlockUnsafe(dest, write_buffer.data(), dst_size); - } - - Texture::UnswizzleSubrect(regs.x_count, regs.y_count, regs.dst_pitch, - regs.src_params.size_x, bytes_per_pixel, read_buffer.data(), - write_buffer.data(), regs.src_params.BlockHeight(), pos_x, - pos_y); - - memory_manager.WriteBlock(dest, write_buffer.data(), dst_size); - - return; - } - // If the input is tiled and the output is linear, deswizzle the input and copy it over. - const u32 bytes_per_pixel = regs.dst_pitch / regs.x_count; - const std::size_t src_size = Texture::CalculateSize( - true, bytes_per_pixel, regs.src_params.size_x, regs.src_params.size_y, - regs.src_params.size_z, regs.src_params.BlockHeight(), regs.src_params.BlockDepth()); - - const std::size_t src_layer_size = Texture::CalculateSize( - true, bytes_per_pixel, regs.src_params.size_x, regs.src_params.size_y, 1, - regs.src_params.BlockHeight(), regs.src_params.BlockDepth()); - - const std::size_t dst_size = regs.dst_pitch * regs.y_count; +void MaxwellDMA::CopyPitchToPitch() { + // When `multi_line_enable` bit is disabled the copy is performed as if we were copying a 1D + // buffer of length `line_length_in`. + // Otherwise we copy a 2D image of dimensions (line_length_in, line_count). + if (!regs.launch_dma.multi_line_enable) { + memory_manager.CopyBlock(regs.offset_out, regs.offset_in, regs.line_length_in); + return; + } - if (read_buffer.size() < src_size) { - read_buffer.resize(src_size); - } + // Perform a line-by-line copy. + // We're going to take a subrect of size (line_length_in, line_count) from the source rectangle. + // There is no need to manually flush/invalidate the regions because CopyBlock does that for us. + for (u32 line = 0; line < regs.line_count; ++line) { + const GPUVAddr source_line = regs.offset_in + static_cast<size_t>(line) * regs.pitch_in; + const GPUVAddr dest_line = regs.offset_out + static_cast<size_t>(line) * regs.pitch_out; + memory_manager.CopyBlock(dest_line, source_line, regs.line_length_in); + } +} - if (write_buffer.size() < dst_size) { - write_buffer.resize(dst_size); - } +void MaxwellDMA::CopyBlockLinearToPitch() { + ASSERT(regs.src_params.block_size.depth == 0); - if (Settings::IsGPULevelExtreme()) { - memory_manager.ReadBlock(source, read_buffer.data(), src_size); - memory_manager.ReadBlock(dest, write_buffer.data(), dst_size); - } else { - memory_manager.ReadBlockUnsafe(source, read_buffer.data(), src_size); - memory_manager.ReadBlockUnsafe(dest, write_buffer.data(), dst_size); - } + // Optimized path for micro copies. + const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count; + if (dst_size < GOB_SIZE && regs.pitch_out <= GOB_SIZE_X) { + FastCopyBlockLinearToPitch(); + return; + } - Texture::UnswizzleSubrect( - regs.x_count, regs.y_count, regs.dst_pitch, regs.src_params.size_x, bytes_per_pixel, - read_buffer.data() + src_layer_size * regs.src_params.pos_z, write_buffer.data(), - regs.src_params.BlockHeight(), regs.src_params.pos_x, regs.src_params.pos_y); + // Deswizzle the input and copy it over. + const u32 bytes_per_pixel = regs.pitch_out / regs.line_length_in; + const Parameters& src_params = regs.src_params; + const u32 width = src_params.width; + const u32 height = src_params.height; + const u32 depth = src_params.depth; + const u32 block_height = src_params.block_size.height; + const u32 block_depth = src_params.block_size.depth; + const size_t src_size = + CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth); + const size_t src_layer_size = + CalculateSize(true, bytes_per_pixel, width, height, 1, block_height, block_depth); + + if (read_buffer.size() < src_size) { + read_buffer.resize(src_size); + } + if (write_buffer.size() < dst_size) { + write_buffer.resize(dst_size); + } - memory_manager.WriteBlock(dest, write_buffer.data(), dst_size); + if (Settings::IsGPULevelExtreme()) { + memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size); + memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size); } else { - ASSERT(regs.dst_params.BlockDepth() == 0); + memory_manager.ReadBlockUnsafe(regs.offset_in, read_buffer.data(), src_size); + memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size); + } - const u32 bytes_per_pixel = regs.src_pitch / regs.x_count; + UnswizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_out, width, bytes_per_pixel, + read_buffer.data() + src_layer_size * src_params.layer, write_buffer.data(), + block_height, src_params.origin.x, src_params.origin.y); - const std::size_t dst_size = Texture::CalculateSize( - true, bytes_per_pixel, regs.dst_params.size_x, regs.dst_params.size_y, - regs.dst_params.size_z, regs.dst_params.BlockHeight(), regs.dst_params.BlockDepth()); + memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size); +} - const std::size_t dst_layer_size = Texture::CalculateSize( - true, bytes_per_pixel, regs.dst_params.size_x, regs.dst_params.size_y, 1, - regs.dst_params.BlockHeight(), regs.dst_params.BlockDepth()); +void MaxwellDMA::CopyPitchToBlockLinear() { + const auto& dst_params = regs.dst_params; + const u32 bytes_per_pixel = regs.pitch_in / regs.line_length_in; + const u32 width = dst_params.width; + const u32 height = dst_params.height; + const u32 depth = dst_params.depth; + const u32 block_height = dst_params.block_size.height; + const u32 block_depth = dst_params.block_size.depth; + const size_t dst_size = + CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth); + const size_t dst_layer_size = + CalculateSize(true, bytes_per_pixel, width, height, 1, block_height, block_depth); + + const size_t src_size = static_cast<size_t>(regs.pitch_in) * regs.line_count; + + if (read_buffer.size() < src_size) { + read_buffer.resize(src_size); + } + if (write_buffer.size() < dst_size) { + write_buffer.resize(dst_size); + } - const std::size_t src_size = regs.src_pitch * regs.y_count; + if (Settings::IsGPULevelExtreme()) { + memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size); + memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size); + } else { + memory_manager.ReadBlockUnsafe(regs.offset_in, read_buffer.data(), src_size); + memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size); + } - if (read_buffer.size() < src_size) { - read_buffer.resize(src_size); - } + // If the input is linear and the output is tiled, swizzle the input and copy it over. + if (regs.dst_params.block_size.depth > 0) { + ASSERT(dst_params.layer == 0); + SwizzleSliceToVoxel(regs.line_length_in, regs.line_count, regs.pitch_in, width, height, + bytes_per_pixel, block_height, block_depth, dst_params.origin.x, + dst_params.origin.y, write_buffer.data(), read_buffer.data()); + } else { + SwizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_in, width, bytes_per_pixel, + write_buffer.data() + dst_layer_size * dst_params.layer, read_buffer.data(), + block_height, dst_params.origin.x, dst_params.origin.y); + } - if (write_buffer.size() < dst_size) { - write_buffer.resize(dst_size); - } + memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size); +} - if (Settings::IsGPULevelExtreme()) { - memory_manager.ReadBlock(source, read_buffer.data(), src_size); - memory_manager.ReadBlock(dest, write_buffer.data(), dst_size); - } else { - memory_manager.ReadBlockUnsafe(source, read_buffer.data(), src_size); - memory_manager.ReadBlockUnsafe(dest, write_buffer.data(), dst_size); - } +void MaxwellDMA::FastCopyBlockLinearToPitch() { + const u32 bytes_per_pixel = regs.pitch_out / regs.line_length_in; + const size_t src_size = GOB_SIZE; + const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count; + u32 pos_x = regs.src_params.origin.x; + u32 pos_y = regs.src_params.origin.y; + const u64 offset = GetGOBOffset(regs.src_params.width, regs.src_params.height, pos_x, pos_y, + regs.src_params.block_size.height, bytes_per_pixel); + const u32 x_in_gob = 64 / bytes_per_pixel; + pos_x = pos_x % x_in_gob; + pos_y = pos_y % 8; + + if (read_buffer.size() < src_size) { + read_buffer.resize(src_size); + } - // If the input is linear and the output is tiled, swizzle the input and copy it over. - Texture::SwizzleSubrect( - regs.x_count, regs.y_count, regs.src_pitch, regs.dst_params.size_x, bytes_per_pixel, - write_buffer.data() + dst_layer_size * regs.dst_params.pos_z, read_buffer.data(), - regs.dst_params.BlockHeight(), regs.dst_params.pos_x, regs.dst_params.pos_y); + if (write_buffer.size() < dst_size) { + write_buffer.resize(dst_size); + } - memory_manager.WriteBlock(dest, write_buffer.data(), dst_size); + if (Settings::IsGPULevelExtreme()) { + memory_manager.ReadBlock(regs.offset_in + offset, read_buffer.data(), src_size); + memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size); + } else { + memory_manager.ReadBlockUnsafe(regs.offset_in + offset, read_buffer.data(), src_size); + memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size); } + + UnswizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_out, regs.src_params.width, + bytes_per_pixel, read_buffer.data(), write_buffer.data(), + regs.src_params.block_size.height, pos_x, pos_y); + + memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size); } } // namespace Tegra::Engines diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h index 502dd8509..50f445efc 100644 --- a/src/video_core/engines/maxwell_dma.h +++ b/src/video_core/engines/maxwell_dma.h @@ -24,160 +24,190 @@ class MemoryManager; namespace Tegra::Engines { /** - * This Engine is known as GK104_Copy. Documentation can be found in: + * This engine is known as gk104_copy. Documentation can be found in: + * https://github.com/NVIDIA/open-gpu-doc/blob/master/classes/dma-copy/clb0b5.h * https://github.com/envytools/envytools/blob/master/rnndb/fifo/gk104_copy.xml */ class MaxwellDMA final : public EngineInterface { public: - explicit MaxwellDMA(Core::System& system, MemoryManager& memory_manager); - ~MaxwellDMA() = default; - - /// Write the value to the register identified by method. - void CallMethod(u32 method, u32 method_argument, bool is_last_call) override; - - /// Write multiple values to the register identified by method. - void CallMultiMethod(u32 method, const u32* base_start, u32 amount, - u32 methods_pending) override; + struct PackedGPUVAddr { + u32 upper; + u32 lower; + + constexpr operator GPUVAddr() const noexcept { + return (static_cast<GPUVAddr>(upper & 0xff) << 32) | lower; + } + }; + + union BlockSize { + BitField<0, 4, u32> width; + BitField<4, 4, u32> height; + BitField<8, 4, u32> depth; + BitField<12, 4, u32> gob_height; + }; + static_assert(sizeof(BlockSize) == 4); + + union Origin { + BitField<0, 16, u32> x; + BitField<16, 16, u32> y; + }; + static_assert(sizeof(Origin) == 4); + + struct Parameters { + BlockSize block_size; + u32 width; + u32 height; + u32 depth; + u32 layer; + Origin origin; + }; + static_assert(sizeof(Parameters) == 24); + + struct Semaphore { + PackedGPUVAddr address; + u32 payload; + }; + static_assert(sizeof(Semaphore) == 12); + + struct RenderEnable { + enum class Mode : u32 { + FALSE = 0, + TRUE = 1, + CONDITIONAL = 2, + RENDER_IF_EQUAL = 3, + RENDER_IF_NOT_EQUAL = 4, + }; - struct Regs { - static constexpr std::size_t NUM_REGS = 0x1D6; + PackedGPUVAddr address; + BitField<0, 3, Mode> mode; + }; + static_assert(sizeof(RenderEnable) == 12); + + enum class PhysModeTarget : u32 { + LOCAL_FB = 0, + COHERENT_SYSMEM = 1, + NONCOHERENT_SYSMEM = 2, + }; + using PhysMode = BitField<0, 2, PhysModeTarget>; + + union LaunchDMA { + enum class DataTransferType : u32 { + NONE = 0, + PIPELINED = 1, + NON_PIPELINED = 2, + }; - struct Parameters { - union { - BitField<0, 4, u32> block_depth; - BitField<4, 4, u32> block_height; - BitField<8, 4, u32> block_width; - }; - u32 size_x; - u32 size_y; - u32 size_z; - u32 pos_z; - union { - BitField<0, 16, u32> pos_x; - BitField<16, 16, u32> pos_y; - }; + enum class SemaphoreType : u32 { + NONE = 0, + RELEASE_ONE_WORD_SEMAPHORE = 1, + RELEASE_FOUR_WORD_SEMAPHORE = 2, + }; - u32 BlockHeight() const { - return block_height.Value(); - } + enum class InterruptType : u32 { + NONE = 0, + BLOCKING = 1, + NON_BLOCKING = 2, + }; - u32 BlockDepth() const { - return block_depth.Value(); - } + enum class MemoryLayout : u32 { + BLOCKLINEAR = 0, + PITCH = 1, }; - static_assert(sizeof(Parameters) == 24, "Parameters has wrong size"); + enum class Type : u32 { + VIRTUAL = 0, + PHYSICAL = 1, + }; - enum class ComponentMode : u32 { - Src0 = 0, - Src1 = 1, - Src2 = 2, - Src3 = 3, - Const0 = 4, - Const1 = 5, - Zero = 6, + enum class SemaphoreReduction : u32 { + IMIN = 0, + IMAX = 1, + IXOR = 2, + IAND = 3, + IOR = 4, + IADD = 5, + INC = 6, + DEC = 7, + FADD = 0xA, }; - enum class CopyMode : u32 { - None = 0, - Unk1 = 1, - Unk2 = 2, + enum class SemaphoreReductionSign : u32 { + SIGNED = 0, + UNSIGNED = 1, }; - enum class QueryMode : u32 { - None = 0, - Short = 1, - Long = 2, + enum class BypassL2 : u32 { + USE_PTE_SETTING = 0, + FORCE_VOLATILE = 1, }; - enum class QueryIntr : u32 { - None = 0, - Block = 1, - NonBlock = 2, + BitField<0, 2, DataTransferType> data_transfer_type; + BitField<2, 1, u32> flush_enable; + BitField<3, 2, SemaphoreType> semaphore_type; + BitField<5, 2, InterruptType> interrupt_type; + BitField<7, 1, MemoryLayout> src_memory_layout; + BitField<8, 1, MemoryLayout> dst_memory_layout; + BitField<9, 1, u32> multi_line_enable; + BitField<10, 1, u32> remap_enable; + BitField<11, 1, u32> rmwdisable; + BitField<12, 1, Type> src_type; + BitField<13, 1, Type> dst_type; + BitField<14, 4, SemaphoreReduction> semaphore_reduction; + BitField<18, 1, SemaphoreReductionSign> semaphore_reduction_sign; + BitField<19, 1, u32> reduction_enable; + BitField<20, 1, BypassL2> bypass_l2; + }; + static_assert(sizeof(LaunchDMA) == 4); + + struct RemapConst { + enum Swizzle : u32 { + SRC_X = 0, + SRC_Y = 1, + SRC_Z = 2, + SRC_W = 3, + CONST_A = 4, + CONST_B = 5, + NO_WRITE = 6, }; - union { - struct { - INSERT_UNION_PADDING_WORDS(0xC0); - - struct { - union { - BitField<0, 2, CopyMode> copy_mode; - BitField<2, 1, u32> flush; - - BitField<3, 2, QueryMode> query_mode; - BitField<5, 2, QueryIntr> query_intr; - - BitField<7, 1, u32> is_src_linear; - BitField<8, 1, u32> is_dst_linear; - - BitField<9, 1, u32> enable_2d; - BitField<10, 1, u32> enable_swizzle; - }; - } exec; - - INSERT_UNION_PADDING_WORDS(0x3F); - - struct { - u32 address_high; - u32 address_low; - - GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); - } - } src_address; - - struct { - u32 address_high; - u32 address_low; - - GPUVAddr Address() const { - return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | - address_low); - } - } dst_address; - - u32 src_pitch; - u32 dst_pitch; - u32 x_count; - u32 y_count; - - INSERT_UNION_PADDING_WORDS(0xB8); - - u32 const0; - u32 const1; - union { - BitField<0, 4, ComponentMode> component0; - BitField<4, 4, ComponentMode> component1; - BitField<8, 4, ComponentMode> component2; - BitField<12, 4, ComponentMode> component3; - BitField<16, 2, u32> component_size; - BitField<20, 3, u32> src_num_components; - BitField<24, 3, u32> dst_num_components; - - u32 SrcBytePerPixel() const { - return src_num_components.Value() * component_size.Value(); - } - u32 DstBytePerPixel() const { - return dst_num_components.Value() * component_size.Value(); - } - } swizzle_config; + PackedGPUVAddr address; - Parameters dst_params; + union { + BitField<0, 3, Swizzle> dst_x; + BitField<4, 3, Swizzle> dst_y; + BitField<8, 3, Swizzle> dst_z; + BitField<12, 3, Swizzle> dst_w; + BitField<16, 2, u32> component_size_minus_one; + BitField<20, 2, u32> num_src_components_minus_one; + BitField<24, 2, u32> num_dst_components_minus_one; + }; + }; + static_assert(sizeof(RemapConst) == 12); - INSERT_UNION_PADDING_WORDS(1); + explicit MaxwellDMA(Core::System& system, MemoryManager& memory_manager); + ~MaxwellDMA() = default; - Parameters src_params; + /// Write the value to the register identified by method. + void CallMethod(u32 method, u32 method_argument, bool is_last_call) override; - INSERT_UNION_PADDING_WORDS(0x13); - }; - std::array<u32, NUM_REGS> reg_array; - }; - } regs{}; + /// Write multiple values to the register identified by method. + void CallMultiMethod(u32 method, const u32* base_start, u32 amount, + u32 methods_pending) override; private: + /// Performs the copy from the source buffer to the destination buffer as configured in the + /// registers. + void Launch(); + + void CopyPitchToPitch(); + + void CopyBlockLinearToPitch(); + + void CopyPitchToBlockLinear(); + + void FastCopyBlockLinearToPitch(); + Core::System& system; MemoryManager& memory_manager; @@ -185,28 +215,58 @@ private: std::vector<u8> read_buffer; std::vector<u8> write_buffer; - /// Performs the copy from the source buffer to the destination buffer as configured in the - /// registers. - void HandleCopy(); -}; + static constexpr std::size_t NUM_REGS = 0x800; + struct Regs { + union { + struct { + u32 reserved[0x40]; + u32 nop; + u32 reserved01[0xf]; + u32 pm_trigger; + u32 reserved02[0x3f]; + Semaphore semaphore; + u32 reserved03[0x2]; + RenderEnable render_enable; + PhysMode src_phys_mode; + PhysMode dst_phys_mode; + u32 reserved04[0x26]; + LaunchDMA launch_dma; + u32 reserved05[0x3f]; + PackedGPUVAddr offset_in; + PackedGPUVAddr offset_out; + u32 pitch_in; + u32 pitch_out; + u32 line_length_in; + u32 line_count; + u32 reserved06[0xb8]; + RemapConst remap_const; + Parameters dst_params; + u32 reserved07[0x1]; + Parameters src_params; + u32 reserved08[0x275]; + u32 pm_trigger_end; + u32 reserved09[0x3ba]; + }; + std::array<u32, NUM_REGS> reg_array; + }; + } regs{}; #define ASSERT_REG_POSITION(field_name, position) \ static_assert(offsetof(MaxwellDMA::Regs, field_name) == position * 4, \ "Field " #field_name " has invalid position") -ASSERT_REG_POSITION(exec, 0xC0); -ASSERT_REG_POSITION(src_address, 0x100); -ASSERT_REG_POSITION(dst_address, 0x102); -ASSERT_REG_POSITION(src_pitch, 0x104); -ASSERT_REG_POSITION(dst_pitch, 0x105); -ASSERT_REG_POSITION(x_count, 0x106); -ASSERT_REG_POSITION(y_count, 0x107); -ASSERT_REG_POSITION(const0, 0x1C0); -ASSERT_REG_POSITION(const1, 0x1C1); -ASSERT_REG_POSITION(swizzle_config, 0x1C2); -ASSERT_REG_POSITION(dst_params, 0x1C3); -ASSERT_REG_POSITION(src_params, 0x1CA); + ASSERT_REG_POSITION(launch_dma, 0xC0); + ASSERT_REG_POSITION(offset_in, 0x100); + ASSERT_REG_POSITION(offset_out, 0x102); + ASSERT_REG_POSITION(pitch_in, 0x104); + ASSERT_REG_POSITION(pitch_out, 0x105); + ASSERT_REG_POSITION(line_length_in, 0x106); + ASSERT_REG_POSITION(line_count, 0x107); + ASSERT_REG_POSITION(remap_const, 0x1C0); + ASSERT_REG_POSITION(dst_params, 0x1C3); + ASSERT_REG_POSITION(src_params, 0x1CA); #undef ASSERT_REG_POSITION +}; } // namespace Tegra::Engines diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index fbd406f2b..866813465 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -141,24 +141,28 @@ struct ScreenRectVertex { std::array<f32, 2> tex_coord; static VkVertexInputBindingDescription GetDescription() { - VkVertexInputBindingDescription description; - description.binding = 0; - description.stride = sizeof(ScreenRectVertex); - description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - return description; + return { + .binding = 0, + .stride = sizeof(ScreenRectVertex), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, + }; } static std::array<VkVertexInputAttributeDescription, 2> GetAttributes() { - std::array<VkVertexInputAttributeDescription, 2> attributes; - attributes[0].location = 0; - attributes[0].binding = 0; - attributes[0].format = VK_FORMAT_R32G32_SFLOAT; - attributes[0].offset = offsetof(ScreenRectVertex, position); - attributes[1].location = 1; - attributes[1].binding = 0; - attributes[1].format = VK_FORMAT_R32G32_SFLOAT; - attributes[1].offset = offsetof(ScreenRectVertex, tex_coord); - return attributes; + return {{ + { + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32_SFLOAT, + .offset = offsetof(ScreenRectVertex, position), + }, + { + .location = 1, + .binding = 0, + .format = VK_FORMAT_R32G32_SFLOAT, + .offset = offsetof(ScreenRectVertex, tex_coord), + }, + }}; } }; @@ -267,20 +271,25 @@ std::tuple<VKFence&, VkSemaphore> VKBlitScreen::Draw(const Tegra::FramebufferCon blit_image->Transition(0, 1, 0, 1, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - VkBufferImageCopy copy; - copy.bufferOffset = image_offset; - copy.bufferRowLength = 0; - copy.bufferImageHeight = 0; - copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copy.imageSubresource.mipLevel = 0; - copy.imageSubresource.baseArrayLayer = 0; - copy.imageSubresource.layerCount = 1; - copy.imageOffset.x = 0; - copy.imageOffset.y = 0; - copy.imageOffset.z = 0; - copy.imageExtent.width = framebuffer.width; - copy.imageExtent.height = framebuffer.height; - copy.imageExtent.depth = 1; + const VkBufferImageCopy copy{ + .bufferOffset = image_offset, + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource = + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .imageOffset = {.x = 0, .y = 0, .z = 0}, + .imageExtent = + { + .width = framebuffer.width, + .height = framebuffer.height, + .depth = 1, + }, + }; scheduler.Record( [buffer = *buffer, image = *blit_image->GetHandle(), copy](vk::CommandBuffer cmdbuf) { cmdbuf.CopyBufferToImage(buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy); @@ -295,11 +304,9 @@ std::tuple<VKFence&, VkSemaphore> VKBlitScreen::Draw(const Tegra::FramebufferCon descriptor_set = descriptor_sets[image_index], buffer = *buffer, size = swapchain.GetSize(), pipeline = *pipeline, layout = *pipeline_layout](vk::CommandBuffer cmdbuf) { - VkClearValue clear_color; - clear_color.color.float32[0] = 0.0f; - clear_color.color.float32[1] = 0.0f; - clear_color.color.float32[2] = 0.0f; - clear_color.color.float32[3] = 0.0f; + const VkClearValue clear_color{ + .color = {.float32 = {0.0f, 0.0f, 0.0f, 0.0f}}, + }; VkRenderPassBeginInfo renderpass_bi; renderpass_bi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; @@ -379,93 +386,109 @@ void VKBlitScreen::CreateSemaphores() { } void VKBlitScreen::CreateDescriptorPool() { - std::array<VkDescriptorPoolSize, 2> pool_sizes; - pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - pool_sizes[0].descriptorCount = static_cast<u32>(image_count); - pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - pool_sizes[1].descriptorCount = static_cast<u32>(image_count); - - VkDescriptorPoolCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - ci.maxSets = static_cast<u32>(image_count); - ci.poolSizeCount = static_cast<u32>(pool_sizes.size()); - ci.pPoolSizes = pool_sizes.data(); + const std::array<VkDescriptorPoolSize, 2> pool_sizes{{ + { + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = static_cast<u32>(image_count), + }, + { + .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .descriptorCount = static_cast<u32>(image_count), + }, + }}; + + const VkDescriptorPoolCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .pNext = nullptr, + .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, + .maxSets = static_cast<u32>(image_count), + .poolSizeCount = static_cast<u32>(pool_sizes.size()), + .pPoolSizes = pool_sizes.data(), + }; descriptor_pool = device.GetLogical().CreateDescriptorPool(ci); } void VKBlitScreen::CreateRenderPass() { - VkAttachmentDescription color_attachment; - color_attachment.flags = 0; - color_attachment.format = swapchain.GetImageFormat(); - color_attachment.samples = VK_SAMPLE_COUNT_1_BIT; - color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - - VkAttachmentReference color_attachment_ref; - color_attachment_ref.attachment = 0; - color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkSubpassDescription subpass_description; - subpass_description.flags = 0; - subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass_description.inputAttachmentCount = 0; - subpass_description.pInputAttachments = nullptr; - subpass_description.colorAttachmentCount = 1; - subpass_description.pColorAttachments = &color_attachment_ref; - subpass_description.pResolveAttachments = nullptr; - subpass_description.pDepthStencilAttachment = nullptr; - subpass_description.preserveAttachmentCount = 0; - subpass_description.pPreserveAttachments = nullptr; - - VkSubpassDependency dependency; - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.srcAccessMask = 0; - dependency.dstAccessMask = - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependency.dependencyFlags = 0; - - VkRenderPassCreateInfo renderpass_ci; - renderpass_ci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderpass_ci.pNext = nullptr; - renderpass_ci.flags = 0; - renderpass_ci.attachmentCount = 1; - renderpass_ci.pAttachments = &color_attachment; - renderpass_ci.subpassCount = 1; - renderpass_ci.pSubpasses = &subpass_description; - renderpass_ci.dependencyCount = 1; - renderpass_ci.pDependencies = &dependency; + const VkAttachmentDescription color_attachment{ + .flags = 0, + .format = swapchain.GetImageFormat(), + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + }; + + const VkAttachmentReference color_attachment_ref{ + .attachment = 0, + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + }; + + const VkSubpassDescription subpass_description{ + .flags = 0, + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .inputAttachmentCount = 0, + .pInputAttachments = nullptr, + .colorAttachmentCount = 1, + .pColorAttachments = &color_attachment_ref, + .pResolveAttachments = nullptr, + .pDepthStencilAttachment = nullptr, + .preserveAttachmentCount = 0, + .pPreserveAttachments = nullptr, + }; + + const VkSubpassDependency dependency{ + .srcSubpass = VK_SUBPASS_EXTERNAL, + .dstSubpass = 0, + .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + .srcAccessMask = 0, + .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + .dependencyFlags = 0, + }; + + const VkRenderPassCreateInfo renderpass_ci{ + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .attachmentCount = 1, + .pAttachments = &color_attachment, + .subpassCount = 1, + .pSubpasses = &subpass_description, + .dependencyCount = 1, + .pDependencies = &dependency, + }; renderpass = device.GetLogical().CreateRenderPass(renderpass_ci); } void VKBlitScreen::CreateDescriptorSetLayout() { - std::array<VkDescriptorSetLayoutBinding, 2> layout_bindings; - layout_bindings[0].binding = 0; - layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - layout_bindings[0].descriptorCount = 1; - layout_bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - layout_bindings[0].pImmutableSamplers = nullptr; - layout_bindings[1].binding = 1; - layout_bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - layout_bindings[1].descriptorCount = 1; - layout_bindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - layout_bindings[1].pImmutableSamplers = nullptr; - - VkDescriptorSetLayoutCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.bindingCount = static_cast<u32>(layout_bindings.size()); - ci.pBindings = layout_bindings.data(); + const std::array<VkDescriptorSetLayoutBinding, 2> layout_bindings{{ + { + .binding = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + .pImmutableSamplers = nullptr, + }, + { + .binding = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + .pImmutableSamplers = nullptr, + }, + }}; + + const VkDescriptorSetLayoutCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .bindingCount = static_cast<u32>(layout_bindings.size()), + .pBindings = layout_bindings.data(), + }; descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(ci); } @@ -473,175 +496,192 @@ void VKBlitScreen::CreateDescriptorSetLayout() { void VKBlitScreen::CreateDescriptorSets() { const std::vector layouts(image_count, *descriptor_set_layout); - VkDescriptorSetAllocateInfo ai; - ai.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - ai.pNext = nullptr; - ai.descriptorPool = *descriptor_pool; - ai.descriptorSetCount = static_cast<u32>(image_count); - ai.pSetLayouts = layouts.data(); + const VkDescriptorSetAllocateInfo ai{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .pNext = nullptr, + .descriptorPool = *descriptor_pool, + .descriptorSetCount = static_cast<u32>(image_count), + .pSetLayouts = layouts.data(), + }; + descriptor_sets = descriptor_pool.Allocate(ai); } void VKBlitScreen::CreatePipelineLayout() { - VkPipelineLayoutCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.setLayoutCount = 1; - ci.pSetLayouts = descriptor_set_layout.address(); - ci.pushConstantRangeCount = 0; - ci.pPushConstantRanges = nullptr; + const VkPipelineLayoutCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .setLayoutCount = 1, + .pSetLayouts = descriptor_set_layout.address(), + .pushConstantRangeCount = 0, + .pPushConstantRanges = nullptr, + }; pipeline_layout = device.GetLogical().CreatePipelineLayout(ci); } void VKBlitScreen::CreateGraphicsPipeline() { - std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages; - shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - shader_stages[0].pNext = nullptr; - shader_stages[0].flags = 0; - shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; - shader_stages[0].module = *vertex_shader; - shader_stages[0].pName = "main"; - shader_stages[0].pSpecializationInfo = nullptr; - shader_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - shader_stages[1].pNext = nullptr; - shader_stages[1].flags = 0; - shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; - shader_stages[1].module = *fragment_shader; - shader_stages[1].pName = "main"; - shader_stages[1].pSpecializationInfo = nullptr; + const std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{{ + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = *vertex_shader, + .pName = "main", + .pSpecializationInfo = nullptr, + }, + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = *fragment_shader, + .pName = "main", + .pSpecializationInfo = nullptr, + }, + }}; const auto vertex_binding_description = ScreenRectVertex::GetDescription(); const auto vertex_attrs_description = ScreenRectVertex::GetAttributes(); - VkPipelineVertexInputStateCreateInfo vertex_input_ci; - vertex_input_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertex_input_ci.pNext = nullptr; - vertex_input_ci.flags = 0; - vertex_input_ci.vertexBindingDescriptionCount = 1; - vertex_input_ci.pVertexBindingDescriptions = &vertex_binding_description; - vertex_input_ci.vertexAttributeDescriptionCount = u32{vertex_attrs_description.size()}; - vertex_input_ci.pVertexAttributeDescriptions = vertex_attrs_description.data(); - - VkPipelineInputAssemblyStateCreateInfo input_assembly_ci; - input_assembly_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - input_assembly_ci.pNext = nullptr; - input_assembly_ci.flags = 0; - input_assembly_ci.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; - input_assembly_ci.primitiveRestartEnable = VK_FALSE; - - VkPipelineViewportStateCreateInfo viewport_state_ci; - viewport_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewport_state_ci.pNext = nullptr; - viewport_state_ci.flags = 0; - viewport_state_ci.viewportCount = 1; - viewport_state_ci.pViewports = nullptr; - viewport_state_ci.scissorCount = 1; - viewport_state_ci.pScissors = nullptr; - - VkPipelineRasterizationStateCreateInfo rasterization_ci; - rasterization_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterization_ci.pNext = nullptr; - rasterization_ci.flags = 0; - rasterization_ci.depthClampEnable = VK_FALSE; - rasterization_ci.rasterizerDiscardEnable = VK_FALSE; - rasterization_ci.polygonMode = VK_POLYGON_MODE_FILL; - rasterization_ci.cullMode = VK_CULL_MODE_NONE; - rasterization_ci.frontFace = VK_FRONT_FACE_CLOCKWISE; - rasterization_ci.depthBiasEnable = VK_FALSE; - rasterization_ci.depthBiasConstantFactor = 0.0f; - rasterization_ci.depthBiasClamp = 0.0f; - rasterization_ci.depthBiasSlopeFactor = 0.0f; - rasterization_ci.lineWidth = 1.0f; - - VkPipelineMultisampleStateCreateInfo multisampling_ci; - multisampling_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling_ci.pNext = nullptr; - multisampling_ci.flags = 0; - multisampling_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - multisampling_ci.sampleShadingEnable = VK_FALSE; - multisampling_ci.minSampleShading = 0.0f; - multisampling_ci.pSampleMask = nullptr; - multisampling_ci.alphaToCoverageEnable = VK_FALSE; - multisampling_ci.alphaToOneEnable = VK_FALSE; - - VkPipelineColorBlendAttachmentState color_blend_attachment; - color_blend_attachment.blendEnable = VK_FALSE; - color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; - color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - - VkPipelineColorBlendStateCreateInfo color_blend_ci; - color_blend_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - color_blend_ci.flags = 0; - color_blend_ci.pNext = nullptr; - color_blend_ci.logicOpEnable = VK_FALSE; - color_blend_ci.logicOp = VK_LOGIC_OP_COPY; - color_blend_ci.attachmentCount = 1; - color_blend_ci.pAttachments = &color_blend_attachment; - color_blend_ci.blendConstants[0] = 0.0f; - color_blend_ci.blendConstants[1] = 0.0f; - color_blend_ci.blendConstants[2] = 0.0f; - color_blend_ci.blendConstants[3] = 0.0f; - - static constexpr std::array dynamic_states = {VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR}; - VkPipelineDynamicStateCreateInfo dynamic_state_ci; - dynamic_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamic_state_ci.pNext = nullptr; - dynamic_state_ci.flags = 0; - dynamic_state_ci.dynamicStateCount = static_cast<u32>(dynamic_states.size()); - dynamic_state_ci.pDynamicStates = dynamic_states.data(); - - VkGraphicsPipelineCreateInfo pipeline_ci; - pipeline_ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipeline_ci.pNext = nullptr; - pipeline_ci.flags = 0; - pipeline_ci.stageCount = static_cast<u32>(shader_stages.size()); - pipeline_ci.pStages = shader_stages.data(); - pipeline_ci.pVertexInputState = &vertex_input_ci; - pipeline_ci.pInputAssemblyState = &input_assembly_ci; - pipeline_ci.pTessellationState = nullptr; - pipeline_ci.pViewportState = &viewport_state_ci; - pipeline_ci.pRasterizationState = &rasterization_ci; - pipeline_ci.pMultisampleState = &multisampling_ci; - pipeline_ci.pDepthStencilState = nullptr; - pipeline_ci.pColorBlendState = &color_blend_ci; - pipeline_ci.pDynamicState = &dynamic_state_ci; - pipeline_ci.layout = *pipeline_layout; - pipeline_ci.renderPass = *renderpass; - pipeline_ci.subpass = 0; - pipeline_ci.basePipelineHandle = 0; - pipeline_ci.basePipelineIndex = 0; + const VkPipelineVertexInputStateCreateInfo vertex_input_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .vertexBindingDescriptionCount = 1, + .pVertexBindingDescriptions = &vertex_binding_description, + .vertexAttributeDescriptionCount = u32{vertex_attrs_description.size()}, + .pVertexAttributeDescriptions = vertex_attrs_description.data(), + }; + + const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, + .primitiveRestartEnable = VK_FALSE, + }; + + const VkPipelineViewportStateCreateInfo viewport_state_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .viewportCount = 1, + .pViewports = nullptr, + .scissorCount = 1, + .pScissors = nullptr, + }; + + const VkPipelineRasterizationStateCreateInfo rasterization_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .depthClampEnable = VK_FALSE, + .rasterizerDiscardEnable = VK_FALSE, + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = VK_CULL_MODE_NONE, + .frontFace = VK_FRONT_FACE_CLOCKWISE, + .depthBiasEnable = VK_FALSE, + .depthBiasConstantFactor = 0.0f, + .depthBiasClamp = 0.0f, + .depthBiasSlopeFactor = 0.0f, + .lineWidth = 1.0f, + }; + + const VkPipelineMultisampleStateCreateInfo multisampling_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + .sampleShadingEnable = VK_FALSE, + .minSampleShading = 0.0f, + .pSampleMask = nullptr, + .alphaToCoverageEnable = VK_FALSE, + .alphaToOneEnable = VK_FALSE, + }; + + const VkPipelineColorBlendAttachmentState color_blend_attachment{ + .blendEnable = VK_FALSE, + .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO, + .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, + .alphaBlendOp = VK_BLEND_OP_ADD, + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, + }; + + const VkPipelineColorBlendStateCreateInfo color_blend_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .logicOpEnable = VK_FALSE, + .logicOp = VK_LOGIC_OP_COPY, + .attachmentCount = 1, + .pAttachments = &color_blend_attachment, + .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, + }; + + static constexpr std::array dynamic_states{ + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + }; + const VkPipelineDynamicStateCreateInfo dynamic_state_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .dynamicStateCount = static_cast<u32>(dynamic_states.size()), + .pDynamicStates = dynamic_states.data(), + }; + + const VkGraphicsPipelineCreateInfo pipeline_ci{ + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .stageCount = static_cast<u32>(shader_stages.size()), + .pStages = shader_stages.data(), + .pVertexInputState = &vertex_input_ci, + .pInputAssemblyState = &input_assembly_ci, + .pTessellationState = nullptr, + .pViewportState = &viewport_state_ci, + .pRasterizationState = &rasterization_ci, + .pMultisampleState = &multisampling_ci, + .pDepthStencilState = nullptr, + .pColorBlendState = &color_blend_ci, + .pDynamicState = &dynamic_state_ci, + .layout = *pipeline_layout, + .renderPass = *renderpass, + .subpass = 0, + .basePipelineHandle = 0, + .basePipelineIndex = 0, + }; pipeline = device.GetLogical().CreateGraphicsPipeline(pipeline_ci); } void VKBlitScreen::CreateSampler() { - VkSamplerCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.magFilter = VK_FILTER_LINEAR; - ci.minFilter = VK_FILTER_NEAREST; - ci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - ci.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - ci.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - ci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - ci.mipLodBias = 0.0f; - ci.anisotropyEnable = VK_FALSE; - ci.maxAnisotropy = 0.0f; - ci.compareEnable = VK_FALSE; - ci.compareOp = VK_COMPARE_OP_NEVER; - ci.minLod = 0.0f; - ci.maxLod = 0.0f; - ci.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; - ci.unnormalizedCoordinates = VK_FALSE; + const VkSamplerCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .magFilter = VK_FILTER_LINEAR, + .minFilter = VK_FILTER_NEAREST, + .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, + .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, + .mipLodBias = 0.0f, + .anisotropyEnable = VK_FALSE, + .maxAnisotropy = 0.0f, + .compareEnable = VK_FALSE, + .compareOp = VK_COMPARE_OP_NEVER, + .minLod = 0.0f, + .maxLod = 0.0f, + .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, + .unnormalizedCoordinates = VK_FALSE, + }; sampler = device.GetLogical().CreateSampler(ci); } @@ -650,15 +690,16 @@ void VKBlitScreen::CreateFramebuffers() { const VkExtent2D size{swapchain.GetSize()}; framebuffers.resize(image_count); - VkFramebufferCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.renderPass = *renderpass; - ci.attachmentCount = 1; - ci.width = size.width; - ci.height = size.height; - ci.layers = 1; + VkFramebufferCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .renderPass = *renderpass, + .attachmentCount = 1, + .width = size.width, + .height = size.height, + .layers = 1, + }; for (std::size_t i = 0; i < image_count; ++i) { const VkImageView image_view{swapchain.GetImageViewIndex(i)}; @@ -678,16 +719,17 @@ void VKBlitScreen::ReleaseRawImages() { } void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { - VkBufferCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.size = CalculateBufferSize(framebuffer); - ci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - ci.queueFamilyIndexCount = 0; - ci.pQueueFamilyIndices = nullptr; + const VkBufferCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .size = CalculateBufferSize(framebuffer), + .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + }; buffer = device.GetLogical().CreateBuffer(ci); buffer_commit = memory_manager.Commit(buffer, true); @@ -697,24 +739,28 @@ void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) raw_images.resize(image_count); raw_buffer_commits.resize(image_count); - VkImageCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.imageType = VK_IMAGE_TYPE_2D; - ci.format = GetFormat(framebuffer); - ci.extent.width = framebuffer.width; - ci.extent.height = framebuffer.height; - ci.extent.depth = 1; - ci.mipLevels = 1; - ci.arrayLayers = 1; - ci.samples = VK_SAMPLE_COUNT_1_BIT; - ci.tiling = VK_IMAGE_TILING_LINEAR; - ci.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - ci.queueFamilyIndexCount = 0; - ci.pQueueFamilyIndices = nullptr; - ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + const VkImageCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .imageType = VK_IMAGE_TYPE_2D, + .format = GetFormat(framebuffer), + .extent = + { + .width = framebuffer.width, + .height = framebuffer.height, + .depth = 1, + }, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_LINEAR, + .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; for (std::size_t i = 0; i < image_count; ++i) { raw_images[i] = std::make_unique<VKImage>(device, scheduler, ci, VK_IMAGE_ASPECT_COLOR_BIT); @@ -723,39 +769,43 @@ void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) } void VKBlitScreen::UpdateDescriptorSet(std::size_t image_index, VkImageView image_view) const { - VkDescriptorBufferInfo buffer_info; - buffer_info.buffer = *buffer; - buffer_info.offset = offsetof(BufferData, uniform); - buffer_info.range = sizeof(BufferData::uniform); - - VkWriteDescriptorSet ubo_write; - ubo_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - ubo_write.pNext = nullptr; - ubo_write.dstSet = descriptor_sets[image_index]; - ubo_write.dstBinding = 0; - ubo_write.dstArrayElement = 0; - ubo_write.descriptorCount = 1; - ubo_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - ubo_write.pImageInfo = nullptr; - ubo_write.pBufferInfo = &buffer_info; - ubo_write.pTexelBufferView = nullptr; - - VkDescriptorImageInfo image_info; - image_info.sampler = *sampler; - image_info.imageView = image_view; - image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - VkWriteDescriptorSet sampler_write; - sampler_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - sampler_write.pNext = nullptr; - sampler_write.dstSet = descriptor_sets[image_index]; - sampler_write.dstBinding = 1; - sampler_write.dstArrayElement = 0; - sampler_write.descriptorCount = 1; - sampler_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - sampler_write.pImageInfo = &image_info; - sampler_write.pBufferInfo = nullptr; - sampler_write.pTexelBufferView = nullptr; + const VkDescriptorBufferInfo buffer_info{ + .buffer = *buffer, + .offset = offsetof(BufferData, uniform), + .range = sizeof(BufferData::uniform), + }; + + const VkWriteDescriptorSet ubo_write{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + .dstSet = descriptor_sets[image_index], + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .pImageInfo = nullptr, + .pBufferInfo = &buffer_info, + .pTexelBufferView = nullptr, + }; + + const VkDescriptorImageInfo image_info{ + .sampler = *sampler, + .imageView = image_view, + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }; + + const VkWriteDescriptorSet sampler_write{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + .dstSet = descriptor_sets[image_index], + .dstBinding = 1, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = &image_info, + .pBufferInfo = nullptr, + .pTexelBufferView = nullptr, + }; device.GetLogical().UpdateDescriptorSets(std::array{ubo_write, sampler_write}, {}); } diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp index fdaea4210..9226e591c 100644 --- a/src/video_core/renderer_vulkan/vk_device.cpp +++ b/src/video_core/renderer_vulkan/vk_device.cpp @@ -22,14 +22,21 @@ namespace { namespace Alternatives { -constexpr std::array Depth24UnormS8_UINT = {VK_FORMAT_D32_SFLOAT_S8_UINT, - VK_FORMAT_D16_UNORM_S8_UINT, VkFormat{}}; -constexpr std::array Depth16UnormS8_UINT = {VK_FORMAT_D24_UNORM_S8_UINT, - VK_FORMAT_D32_SFLOAT_S8_UINT, VkFormat{}}; +constexpr std::array Depth24UnormS8_UINT{ + VK_FORMAT_D32_SFLOAT_S8_UINT, + VK_FORMAT_D16_UNORM_S8_UINT, + VkFormat{}, +}; + +constexpr std::array Depth16UnormS8_UINT{ + VK_FORMAT_D24_UNORM_S8_UINT, + VK_FORMAT_D32_SFLOAT_S8_UINT, + VkFormat{}, +}; } // namespace Alternatives -constexpr std::array REQUIRED_EXTENSIONS = { +constexpr std::array REQUIRED_EXTENSIONS{ VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_16BIT_STORAGE_EXTENSION_NAME, VK_KHR_8BIT_STORAGE_EXTENSION_NAME, @@ -169,97 +176,104 @@ bool VKDevice::Create() { const auto queue_cis = GetDeviceQueueCreateInfos(); const std::vector extensions = LoadExtensions(); - VkPhysicalDeviceFeatures2 features2; - features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features2.pNext = nullptr; + VkPhysicalDeviceFeatures2 features2{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + .pNext = nullptr, + }; const void* first_next = &features2; void** next = &features2.pNext; - auto& features = features2.features; - features.robustBufferAccess = false; - features.fullDrawIndexUint32 = false; - features.imageCubeArray = false; - features.independentBlend = true; - features.geometryShader = true; - features.tessellationShader = true; - features.sampleRateShading = false; - features.dualSrcBlend = false; - features.logicOp = false; - features.multiDrawIndirect = false; - features.drawIndirectFirstInstance = false; - features.depthClamp = true; - features.depthBiasClamp = true; - features.fillModeNonSolid = false; - features.depthBounds = false; - features.wideLines = false; - features.largePoints = true; - features.alphaToOne = false; - features.multiViewport = true; - features.samplerAnisotropy = true; - features.textureCompressionETC2 = false; - features.textureCompressionASTC_LDR = is_optimal_astc_supported; - features.textureCompressionBC = false; - features.occlusionQueryPrecise = true; - features.pipelineStatisticsQuery = false; - features.vertexPipelineStoresAndAtomics = true; - features.fragmentStoresAndAtomics = true; - features.shaderTessellationAndGeometryPointSize = false; - features.shaderImageGatherExtended = true; - features.shaderStorageImageExtendedFormats = false; - features.shaderStorageImageMultisample = false; - features.shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported; - features.shaderStorageImageWriteWithoutFormat = true; - features.shaderUniformBufferArrayDynamicIndexing = false; - features.shaderSampledImageArrayDynamicIndexing = false; - features.shaderStorageBufferArrayDynamicIndexing = false; - features.shaderStorageImageArrayDynamicIndexing = false; - features.shaderClipDistance = false; - features.shaderCullDistance = false; - features.shaderFloat64 = false; - features.shaderInt64 = false; - features.shaderInt16 = false; - features.shaderResourceResidency = false; - features.shaderResourceMinLod = false; - features.sparseBinding = false; - features.sparseResidencyBuffer = false; - features.sparseResidencyImage2D = false; - features.sparseResidencyImage3D = false; - features.sparseResidency2Samples = false; - features.sparseResidency4Samples = false; - features.sparseResidency8Samples = false; - features.sparseResidency16Samples = false; - features.sparseResidencyAliased = false; - features.variableMultisampleRate = false; - features.inheritedQueries = false; - - VkPhysicalDevice16BitStorageFeaturesKHR bit16_storage; - bit16_storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR; - bit16_storage.pNext = nullptr; - bit16_storage.storageBuffer16BitAccess = false; - bit16_storage.uniformAndStorageBuffer16BitAccess = true; - bit16_storage.storagePushConstant16 = false; - bit16_storage.storageInputOutput16 = false; + features2.features = { + .robustBufferAccess = false, + .fullDrawIndexUint32 = false, + .imageCubeArray = false, + .independentBlend = true, + .geometryShader = true, + .tessellationShader = true, + .sampleRateShading = false, + .dualSrcBlend = false, + .logicOp = false, + .multiDrawIndirect = false, + .drawIndirectFirstInstance = false, + .depthClamp = true, + .depthBiasClamp = true, + .fillModeNonSolid = false, + .depthBounds = false, + .wideLines = false, + .largePoints = true, + .alphaToOne = false, + .multiViewport = true, + .samplerAnisotropy = true, + .textureCompressionETC2 = false, + .textureCompressionASTC_LDR = is_optimal_astc_supported, + .textureCompressionBC = false, + .occlusionQueryPrecise = true, + .pipelineStatisticsQuery = false, + .vertexPipelineStoresAndAtomics = true, + .fragmentStoresAndAtomics = true, + .shaderTessellationAndGeometryPointSize = false, + .shaderImageGatherExtended = true, + .shaderStorageImageExtendedFormats = false, + .shaderStorageImageMultisample = false, + .shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported, + .shaderStorageImageWriteWithoutFormat = true, + .shaderUniformBufferArrayDynamicIndexing = false, + .shaderSampledImageArrayDynamicIndexing = false, + .shaderStorageBufferArrayDynamicIndexing = false, + .shaderStorageImageArrayDynamicIndexing = false, + .shaderClipDistance = false, + .shaderCullDistance = false, + .shaderFloat64 = false, + .shaderInt64 = false, + .shaderInt16 = false, + .shaderResourceResidency = false, + .shaderResourceMinLod = false, + .sparseBinding = false, + .sparseResidencyBuffer = false, + .sparseResidencyImage2D = false, + .sparseResidencyImage3D = false, + .sparseResidency2Samples = false, + .sparseResidency4Samples = false, + .sparseResidency8Samples = false, + .sparseResidency16Samples = false, + .sparseResidencyAliased = false, + .variableMultisampleRate = false, + .inheritedQueries = false, + }; + + VkPhysicalDevice16BitStorageFeaturesKHR bit16_storage{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR, + .pNext = nullptr, + .storageBuffer16BitAccess = false, + .uniformAndStorageBuffer16BitAccess = true, + .storagePushConstant16 = false, + .storageInputOutput16 = false, + }; SetNext(next, bit16_storage); - VkPhysicalDevice8BitStorageFeaturesKHR bit8_storage; - bit8_storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR; - bit8_storage.pNext = nullptr; - bit8_storage.storageBuffer8BitAccess = false; - bit8_storage.uniformAndStorageBuffer8BitAccess = true; - bit8_storage.storagePushConstant8 = false; + VkPhysicalDevice8BitStorageFeaturesKHR bit8_storage{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR, + .pNext = nullptr, + .storageBuffer8BitAccess = false, + .uniformAndStorageBuffer8BitAccess = true, + .storagePushConstant8 = false, + }; SetNext(next, bit8_storage); - VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset; - host_query_reset.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT; - host_query_reset.hostQueryReset = true; + VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT, + .hostQueryReset = true, + }; SetNext(next, host_query_reset); VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8; if (is_float16_supported) { - float16_int8.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR; - float16_int8.pNext = nullptr; - float16_int8.shaderFloat16 = true; - float16_int8.shaderInt8 = false; + float16_int8 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR, + .pNext = nullptr, + .shaderFloat16 = true, + .shaderInt8 = false, + }; SetNext(next, float16_int8); } else { LOG_INFO(Render_Vulkan, "Device doesn't support float16 natively"); @@ -271,10 +285,11 @@ bool VKDevice::Create() { VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR std430_layout; if (khr_uniform_buffer_standard_layout) { - std430_layout.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR; - std430_layout.pNext = nullptr; - std430_layout.uniformBufferStandardLayout = true; + std430_layout = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR, + .pNext = nullptr, + .uniformBufferStandardLayout = true, + }; SetNext(next, std430_layout); } else { LOG_INFO(Render_Vulkan, "Device doesn't support packed UBOs"); @@ -282,9 +297,11 @@ bool VKDevice::Create() { VkPhysicalDeviceIndexTypeUint8FeaturesEXT index_type_uint8; if (ext_index_type_uint8) { - index_type_uint8.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT; - index_type_uint8.pNext = nullptr; - index_type_uint8.indexTypeUint8 = true; + index_type_uint8 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT, + .pNext = nullptr, + .indexTypeUint8 = true, + }; SetNext(next, index_type_uint8); } else { LOG_INFO(Render_Vulkan, "Device doesn't support uint8 indexes"); @@ -292,11 +309,12 @@ bool VKDevice::Create() { VkPhysicalDeviceTransformFeedbackFeaturesEXT transform_feedback; if (ext_transform_feedback) { - transform_feedback.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT; - transform_feedback.pNext = nullptr; - transform_feedback.transformFeedback = true; - transform_feedback.geometryStreams = true; + transform_feedback = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT, + .pNext = nullptr, + .transformFeedback = true, + .geometryStreams = true, + }; SetNext(next, transform_feedback); } else { LOG_INFO(Render_Vulkan, "Device doesn't support transform feedbacks"); @@ -304,10 +322,12 @@ bool VKDevice::Create() { VkPhysicalDeviceCustomBorderColorFeaturesEXT custom_border; if (ext_custom_border_color) { - custom_border.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT; - custom_border.pNext = nullptr; - custom_border.customBorderColors = VK_TRUE; - custom_border.customBorderColorWithoutFormat = VK_TRUE; + custom_border = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT, + .pNext = nullptr, + .customBorderColors = VK_TRUE, + .customBorderColorWithoutFormat = VK_TRUE, + }; SetNext(next, custom_border); } else { LOG_INFO(Render_Vulkan, "Device doesn't support custom border colors"); @@ -315,9 +335,11 @@ bool VKDevice::Create() { VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state; if (ext_extended_dynamic_state) { - dynamic_state.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; - dynamic_state.pNext = nullptr; - dynamic_state.extendedDynamicState = VK_TRUE; + dynamic_state = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT, + .pNext = nullptr, + .extendedDynamicState = VK_TRUE, + }; SetNext(next, dynamic_state); } else { LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state"); @@ -331,11 +353,13 @@ bool VKDevice::Create() { if (nv_device_diagnostics_config) { nsight_aftermath_tracker.Initialize(); - diagnostics_nv.sType = VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV; - diagnostics_nv.pNext = &features2; - diagnostics_nv.flags = VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV | - VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV | - VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV; + diagnostics_nv = { + .sType = VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV, + .pNext = &features2, + .flags = VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV | + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV | + VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV, + }; first_next = &diagnostics_nv; } @@ -704,13 +728,15 @@ void VKDevice::SetupFeatures() { } void VKDevice::CollectTelemetryParameters() { - VkPhysicalDeviceDriverPropertiesKHR driver; - driver.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR; - driver.pNext = nullptr; + VkPhysicalDeviceDriverPropertiesKHR driver{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR, + .pNext = nullptr, + }; - VkPhysicalDeviceProperties2KHR properties; - properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; - properties.pNext = &driver; + VkPhysicalDeviceProperties2KHR properties{ + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR, + .pNext = &driver, + }; physical.GetProperties2KHR(properties); driver_id = driver.driverID; @@ -719,24 +745,26 @@ void VKDevice::CollectTelemetryParameters() { const std::vector extensions = physical.EnumerateDeviceExtensionProperties(); reported_extensions.reserve(std::size(extensions)); for (const auto& extension : extensions) { - reported_extensions.push_back(extension.extensionName); + reported_extensions.emplace_back(extension.extensionName); } } std::vector<VkDeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() const { static constexpr float QUEUE_PRIORITY = 1.0f; - std::unordered_set<u32> unique_queue_families = {graphics_family, present_family}; + std::unordered_set<u32> unique_queue_families{graphics_family, present_family}; std::vector<VkDeviceQueueCreateInfo> queue_cis; + queue_cis.reserve(unique_queue_families.size()); for (const u32 queue_family : unique_queue_families) { - VkDeviceQueueCreateInfo& ci = queue_cis.emplace_back(); - ci.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.queueFamilyIndex = queue_family; - ci.queueCount = 1; - ci.pQueuePriorities = &QUEUE_PRIORITY; + queue_cis.push_back({ + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .queueFamilyIndex = queue_family, + .queueCount = 1, + .pQueuePriorities = &QUEUE_PRIORITY, + }); } return queue_cis; diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 844445105..aaf930b90 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -28,15 +28,15 @@ namespace { template <class StencilFace> VkStencilOpState GetStencilFaceState(const StencilFace& face) { - VkStencilOpState state; - state.failOp = MaxwellToVK::StencilOp(face.ActionStencilFail()); - state.passOp = MaxwellToVK::StencilOp(face.ActionDepthPass()); - state.depthFailOp = MaxwellToVK::StencilOp(face.ActionDepthFail()); - state.compareOp = MaxwellToVK::ComparisonOp(face.TestFunc()); - state.compareMask = 0; - state.writeMask = 0; - state.reference = 0; - return state; + return { + .failOp = MaxwellToVK::StencilOp(face.ActionStencilFail()), + .passOp = MaxwellToVK::StencilOp(face.ActionDepthPass()), + .depthFailOp = MaxwellToVK::StencilOp(face.ActionDepthFail()), + .compareOp = MaxwellToVK::ComparisonOp(face.TestFunc()), + .compareMask = 0, + .writeMask = 0, + .reference = 0, + }; } bool SupportsPrimitiveRestart(VkPrimitiveTopology topology) { @@ -52,20 +52,21 @@ bool SupportsPrimitiveRestart(VkPrimitiveTopology topology) { } VkViewportSwizzleNV UnpackViewportSwizzle(u16 swizzle) { - union { + union Swizzle { u32 raw; BitField<0, 3, Maxwell::ViewportSwizzle> x; BitField<4, 3, Maxwell::ViewportSwizzle> y; BitField<8, 3, Maxwell::ViewportSwizzle> z; BitField<12, 3, Maxwell::ViewportSwizzle> w; - } const unpacked{swizzle}; - - VkViewportSwizzleNV result; - result.x = MaxwellToVK::ViewportSwizzle(unpacked.x); - result.y = MaxwellToVK::ViewportSwizzle(unpacked.y); - result.z = MaxwellToVK::ViewportSwizzle(unpacked.z); - result.w = MaxwellToVK::ViewportSwizzle(unpacked.w); - return result; + }; + const Swizzle unpacked{swizzle}; + + return { + .x = MaxwellToVK::ViewportSwizzle(unpacked.x), + .y = MaxwellToVK::ViewportSwizzle(unpacked.y), + .z = MaxwellToVK::ViewportSwizzle(unpacked.z), + .w = MaxwellToVK::ViewportSwizzle(unpacked.w), + }; } } // Anonymous namespace @@ -100,24 +101,26 @@ VkDescriptorSet VKGraphicsPipeline::CommitDescriptorSet() { vk::DescriptorSetLayout VKGraphicsPipeline::CreateDescriptorSetLayout( vk::Span<VkDescriptorSetLayoutBinding> bindings) const { - VkDescriptorSetLayoutCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.bindingCount = bindings.size(); - ci.pBindings = bindings.data(); + const VkDescriptorSetLayoutCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .bindingCount = bindings.size(), + .pBindings = bindings.data(), + }; return device.GetLogical().CreateDescriptorSetLayout(ci); } vk::PipelineLayout VKGraphicsPipeline::CreatePipelineLayout() const { - VkPipelineLayoutCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.setLayoutCount = 1; - ci.pSetLayouts = descriptor_set_layout.address(); - ci.pushConstantRangeCount = 0; - ci.pPushConstantRanges = nullptr; + const VkPipelineLayoutCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .setLayoutCount = 1, + .pSetLayouts = descriptor_set_layout.address(), + .pushConstantRangeCount = 0, + .pPushConstantRanges = nullptr, + }; return device.GetLogical().CreatePipelineLayout(ci); } @@ -136,26 +139,28 @@ vk::DescriptorUpdateTemplateKHR VKGraphicsPipeline::CreateDescriptorUpdateTempla return {}; } - VkDescriptorUpdateTemplateCreateInfoKHR ci; - ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR; - ci.pNext = nullptr; - ci.flags = 0; - ci.descriptorUpdateEntryCount = static_cast<u32>(template_entries.size()); - ci.pDescriptorUpdateEntries = template_entries.data(); - ci.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR; - ci.descriptorSetLayout = *descriptor_set_layout; - ci.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - ci.pipelineLayout = *layout; - ci.set = DESCRIPTOR_SET; + const VkDescriptorUpdateTemplateCreateInfoKHR ci{ + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR, + .pNext = nullptr, + .flags = 0, + .descriptorUpdateEntryCount = static_cast<u32>(template_entries.size()), + .pDescriptorUpdateEntries = template_entries.data(), + .templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR, + .descriptorSetLayout = *descriptor_set_layout, + .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .pipelineLayout = *layout, + .set = DESCRIPTOR_SET, + }; return device.GetLogical().CreateDescriptorUpdateTemplateKHR(ci); } std::vector<vk::ShaderModule> VKGraphicsPipeline::CreateShaderModules( const SPIRVProgram& program) const { - VkShaderModuleCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; + VkShaderModuleCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + }; std::vector<vk::ShaderModule> modules; modules.reserve(Maxwell::MaxShaderStage); @@ -204,15 +209,17 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa const bool instanced = state.binding_divisors[index] != 0; const auto rate = instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX; - auto& vertex_binding = vertex_bindings.emplace_back(); - vertex_binding.binding = static_cast<u32>(index); - vertex_binding.stride = binding.stride; - vertex_binding.inputRate = rate; + vertex_bindings.push_back({ + .binding = static_cast<u32>(index), + .stride = binding.stride, + .inputRate = rate, + }); if (instanced) { - auto& binding_divisor = vertex_binding_divisors.emplace_back(); - binding_divisor.binding = static_cast<u32>(index); - binding_divisor.divisor = state.binding_divisors[index]; + vertex_binding_divisors.push_back({ + .binding = static_cast<u32>(index), + .divisor = state.binding_divisors[index], + }); } } @@ -227,116 +234,132 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa // Skip attributes not used by the vertex shaders. continue; } - auto& vertex_attribute = vertex_attributes.emplace_back(); - vertex_attribute.location = static_cast<u32>(index); - vertex_attribute.binding = attribute.buffer; - vertex_attribute.format = MaxwellToVK::VertexFormat(attribute.Type(), attribute.Size()); - vertex_attribute.offset = attribute.offset; + vertex_attributes.push_back({ + .location = static_cast<u32>(index), + .binding = attribute.buffer, + .format = MaxwellToVK::VertexFormat(attribute.Type(), attribute.Size()), + .offset = attribute.offset, + }); } - VkPipelineVertexInputStateCreateInfo vertex_input_ci; - vertex_input_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertex_input_ci.pNext = nullptr; - vertex_input_ci.flags = 0; - vertex_input_ci.vertexBindingDescriptionCount = static_cast<u32>(vertex_bindings.size()); - vertex_input_ci.pVertexBindingDescriptions = vertex_bindings.data(); - vertex_input_ci.vertexAttributeDescriptionCount = static_cast<u32>(vertex_attributes.size()); - vertex_input_ci.pVertexAttributeDescriptions = vertex_attributes.data(); - - VkPipelineVertexInputDivisorStateCreateInfoEXT input_divisor_ci; - input_divisor_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT; - input_divisor_ci.pNext = nullptr; - input_divisor_ci.vertexBindingDivisorCount = static_cast<u32>(vertex_binding_divisors.size()); - input_divisor_ci.pVertexBindingDivisors = vertex_binding_divisors.data(); + VkPipelineVertexInputStateCreateInfo vertex_input_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .vertexBindingDescriptionCount = static_cast<u32>(vertex_bindings.size()), + .pVertexBindingDescriptions = vertex_bindings.data(), + .vertexAttributeDescriptionCount = static_cast<u32>(vertex_attributes.size()), + .pVertexAttributeDescriptions = vertex_attributes.data(), + }; + + const VkPipelineVertexInputDivisorStateCreateInfoEXT input_divisor_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT, + .pNext = nullptr, + .vertexBindingDivisorCount = static_cast<u32>(vertex_binding_divisors.size()), + .pVertexBindingDivisors = vertex_binding_divisors.data(), + }; if (!vertex_binding_divisors.empty()) { vertex_input_ci.pNext = &input_divisor_ci; } - VkPipelineInputAssemblyStateCreateInfo input_assembly_ci; - input_assembly_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - input_assembly_ci.pNext = nullptr; - input_assembly_ci.flags = 0; - input_assembly_ci.topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()); - input_assembly_ci.primitiveRestartEnable = - state.primitive_restart_enable != 0 && SupportsPrimitiveRestart(input_assembly_ci.topology); - - VkPipelineTessellationStateCreateInfo tessellation_ci; - tessellation_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; - tessellation_ci.pNext = nullptr; - tessellation_ci.flags = 0; - tessellation_ci.patchControlPoints = state.patch_control_points_minus_one.Value() + 1; - - VkPipelineViewportStateCreateInfo viewport_ci; - viewport_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewport_ci.pNext = nullptr; - viewport_ci.flags = 0; - viewport_ci.viewportCount = Maxwell::NumViewports; - viewport_ci.pViewports = nullptr; - viewport_ci.scissorCount = Maxwell::NumViewports; - viewport_ci.pScissors = nullptr; + const auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()); + const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .topology = MaxwellToVK::PrimitiveTopology(device, dynamic.Topology()), + .primitiveRestartEnable = state.primitive_restart_enable != 0 && + SupportsPrimitiveRestart(input_assembly_topology), + }; + + const VkPipelineTessellationStateCreateInfo tessellation_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .patchControlPoints = state.patch_control_points_minus_one.Value() + 1, + }; + + VkPipelineViewportStateCreateInfo viewport_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .viewportCount = Maxwell::NumViewports, + .pViewports = nullptr, + .scissorCount = Maxwell::NumViewports, + .pScissors = nullptr, + }; std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles; std::transform(viewport_swizzles.begin(), viewport_swizzles.end(), swizzles.begin(), UnpackViewportSwizzle); - VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci; - swizzle_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV; - swizzle_ci.pNext = nullptr; - swizzle_ci.flags = 0; - swizzle_ci.viewportCount = Maxwell::NumViewports; - swizzle_ci.pViewportSwizzles = swizzles.data(); + VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV, + .pNext = nullptr, + .flags = 0, + .viewportCount = Maxwell::NumViewports, + .pViewportSwizzles = swizzles.data(), + }; if (device.IsNvViewportSwizzleSupported()) { viewport_ci.pNext = &swizzle_ci; } - VkPipelineRasterizationStateCreateInfo rasterization_ci; - rasterization_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterization_ci.pNext = nullptr; - rasterization_ci.flags = 0; - rasterization_ci.depthClampEnable = state.depth_clamp_disabled == 0 ? VK_TRUE : VK_FALSE; - rasterization_ci.rasterizerDiscardEnable = state.rasterize_enable == 0 ? VK_TRUE : VK_FALSE; - rasterization_ci.polygonMode = VK_POLYGON_MODE_FILL; - rasterization_ci.cullMode = - dynamic.cull_enable ? MaxwellToVK::CullFace(dynamic.CullFace()) : VK_CULL_MODE_NONE; - rasterization_ci.frontFace = MaxwellToVK::FrontFace(dynamic.FrontFace()); - rasterization_ci.depthBiasEnable = state.depth_bias_enable; - rasterization_ci.depthBiasConstantFactor = 0.0f; - rasterization_ci.depthBiasClamp = 0.0f; - rasterization_ci.depthBiasSlopeFactor = 0.0f; - rasterization_ci.lineWidth = 1.0f; - - VkPipelineMultisampleStateCreateInfo multisample_ci; - multisample_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisample_ci.pNext = nullptr; - multisample_ci.flags = 0; - multisample_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - multisample_ci.sampleShadingEnable = VK_FALSE; - multisample_ci.minSampleShading = 0.0f; - multisample_ci.pSampleMask = nullptr; - multisample_ci.alphaToCoverageEnable = VK_FALSE; - multisample_ci.alphaToOneEnable = VK_FALSE; - - VkPipelineDepthStencilStateCreateInfo depth_stencil_ci; - depth_stencil_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depth_stencil_ci.pNext = nullptr; - depth_stencil_ci.flags = 0; - depth_stencil_ci.depthTestEnable = dynamic.depth_test_enable; - depth_stencil_ci.depthWriteEnable = dynamic.depth_write_enable; - depth_stencil_ci.depthCompareOp = dynamic.depth_test_enable - ? MaxwellToVK::ComparisonOp(dynamic.DepthTestFunc()) - : VK_COMPARE_OP_ALWAYS; - depth_stencil_ci.depthBoundsTestEnable = dynamic.depth_bounds_enable; - depth_stencil_ci.stencilTestEnable = dynamic.stencil_enable; - depth_stencil_ci.front = GetStencilFaceState(dynamic.front); - depth_stencil_ci.back = GetStencilFaceState(dynamic.back); - depth_stencil_ci.minDepthBounds = 0.0f; - depth_stencil_ci.maxDepthBounds = 0.0f; + const VkPipelineRasterizationStateCreateInfo rasterization_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .depthClampEnable = + static_cast<VkBool32>(state.depth_clamp_disabled == 0 ? VK_TRUE : VK_FALSE), + .rasterizerDiscardEnable = + static_cast<VkBool32>(state.rasterize_enable == 0 ? VK_TRUE : VK_FALSE), + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = + dynamic.cull_enable ? MaxwellToVK::CullFace(dynamic.CullFace()) : VK_CULL_MODE_NONE, + .frontFace = MaxwellToVK::FrontFace(dynamic.FrontFace()), + .depthBiasEnable = state.depth_bias_enable, + .depthBiasConstantFactor = 0.0f, + .depthBiasClamp = 0.0f, + .depthBiasSlopeFactor = 0.0f, + .lineWidth = 1.0f, + }; + + const VkPipelineMultisampleStateCreateInfo multisample_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + .sampleShadingEnable = VK_FALSE, + .minSampleShading = 0.0f, + .pSampleMask = nullptr, + .alphaToCoverageEnable = VK_FALSE, + .alphaToOneEnable = VK_FALSE, + }; + + const VkPipelineDepthStencilStateCreateInfo depth_stencil_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .depthTestEnable = dynamic.depth_test_enable, + .depthWriteEnable = dynamic.depth_write_enable, + .depthCompareOp = dynamic.depth_test_enable + ? MaxwellToVK::ComparisonOp(dynamic.DepthTestFunc()) + : VK_COMPARE_OP_ALWAYS, + .depthBoundsTestEnable = dynamic.depth_bounds_enable, + .stencilTestEnable = dynamic.stencil_enable, + .front = GetStencilFaceState(dynamic.front), + .back = GetStencilFaceState(dynamic.back), + .minDepthBounds = 0.0f, + .maxDepthBounds = 0.0f, + }; std::array<VkPipelineColorBlendAttachmentState, Maxwell::NumRenderTargets> cb_attachments; const auto num_attachments = static_cast<std::size_t>(renderpass_params.num_color_attachments); for (std::size_t index = 0; index < num_attachments; ++index) { - static constexpr std::array COMPONENT_TABLE = { - VK_COLOR_COMPONENT_R_BIT, VK_COLOR_COMPONENT_G_BIT, VK_COLOR_COMPONENT_B_BIT, - VK_COLOR_COMPONENT_A_BIT}; + static constexpr std::array COMPONENT_TABLE{ + VK_COLOR_COMPONENT_R_BIT, + VK_COLOR_COMPONENT_G_BIT, + VK_COLOR_COMPONENT_B_BIT, + VK_COLOR_COMPONENT_A_BIT, + }; const auto& blend = state.attachments[index]; VkColorComponentFlags color_components = 0; @@ -346,35 +369,36 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa } } - VkPipelineColorBlendAttachmentState& attachment = cb_attachments[index]; - attachment.blendEnable = blend.enable != 0; - attachment.srcColorBlendFactor = MaxwellToVK::BlendFactor(blend.SourceRGBFactor()); - attachment.dstColorBlendFactor = MaxwellToVK::BlendFactor(blend.DestRGBFactor()); - attachment.colorBlendOp = MaxwellToVK::BlendEquation(blend.EquationRGB()); - attachment.srcAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.SourceAlphaFactor()); - attachment.dstAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.DestAlphaFactor()); - attachment.alphaBlendOp = MaxwellToVK::BlendEquation(blend.EquationAlpha()); - attachment.colorWriteMask = color_components; + cb_attachments[index] = { + .blendEnable = blend.enable != 0, + .srcColorBlendFactor = MaxwellToVK::BlendFactor(blend.SourceRGBFactor()), + .dstColorBlendFactor = MaxwellToVK::BlendFactor(blend.DestRGBFactor()), + .colorBlendOp = MaxwellToVK::BlendEquation(blend.EquationRGB()), + .srcAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.SourceAlphaFactor()), + .dstAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.DestAlphaFactor()), + .alphaBlendOp = MaxwellToVK::BlendEquation(blend.EquationAlpha()), + .colorWriteMask = color_components, + }; } - VkPipelineColorBlendStateCreateInfo color_blend_ci; - color_blend_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - color_blend_ci.pNext = nullptr; - color_blend_ci.flags = 0; - color_blend_ci.logicOpEnable = VK_FALSE; - color_blend_ci.logicOp = VK_LOGIC_OP_COPY; - color_blend_ci.attachmentCount = static_cast<u32>(num_attachments); - color_blend_ci.pAttachments = cb_attachments.data(); - std::memset(color_blend_ci.blendConstants, 0, sizeof(color_blend_ci.blendConstants)); - - std::vector dynamic_states = { + const VkPipelineColorBlendStateCreateInfo color_blend_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .logicOpEnable = VK_FALSE, + .logicOp = VK_LOGIC_OP_COPY, + .attachmentCount = static_cast<u32>(num_attachments), + .pAttachments = cb_attachments.data(), + }; + + std::vector dynamic_states{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_BLEND_CONSTANTS, VK_DYNAMIC_STATE_DEPTH_BOUNDS, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE, }; if (device.IsExtExtendedDynamicStateSupported()) { - static constexpr std::array extended = { + static constexpr std::array extended{ VK_DYNAMIC_STATE_CULL_MODE_EXT, VK_DYNAMIC_STATE_FRONT_FACE_EXT, VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT, @@ -389,18 +413,19 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa dynamic_states.insert(dynamic_states.end(), extended.begin(), extended.end()); } - VkPipelineDynamicStateCreateInfo dynamic_state_ci; - dynamic_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamic_state_ci.pNext = nullptr; - dynamic_state_ci.flags = 0; - dynamic_state_ci.dynamicStateCount = static_cast<u32>(dynamic_states.size()); - dynamic_state_ci.pDynamicStates = dynamic_states.data(); + const VkPipelineDynamicStateCreateInfo dynamic_state_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .dynamicStateCount = static_cast<u32>(dynamic_states.size()), + .pDynamicStates = dynamic_states.data(), + }; - VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_ci; - subgroup_size_ci.sType = - VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT; - subgroup_size_ci.pNext = nullptr; - subgroup_size_ci.requiredSubgroupSize = GuestWarpSize; + const VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_ci{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT, + .pNext = nullptr, + .requiredSubgroupSize = GuestWarpSize, + }; std::vector<VkPipelineShaderStageCreateInfo> shader_stages; std::size_t module_index = 0; @@ -408,6 +433,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa if (!program[stage]) { continue; } + VkPipelineShaderStageCreateInfo& stage_ci = shader_stages.emplace_back(); stage_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; stage_ci.pNext = nullptr; @@ -422,26 +448,27 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa } } - VkGraphicsPipelineCreateInfo ci; - ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - ci.pNext = nullptr; - ci.flags = 0; - ci.stageCount = static_cast<u32>(shader_stages.size()); - ci.pStages = shader_stages.data(); - ci.pVertexInputState = &vertex_input_ci; - ci.pInputAssemblyState = &input_assembly_ci; - ci.pTessellationState = &tessellation_ci; - ci.pViewportState = &viewport_ci; - ci.pRasterizationState = &rasterization_ci; - ci.pMultisampleState = &multisample_ci; - ci.pDepthStencilState = &depth_stencil_ci; - ci.pColorBlendState = &color_blend_ci; - ci.pDynamicState = &dynamic_state_ci; - ci.layout = *layout; - ci.renderPass = renderpass; - ci.subpass = 0; - ci.basePipelineHandle = nullptr; - ci.basePipelineIndex = 0; + const VkGraphicsPipelineCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .stageCount = static_cast<u32>(shader_stages.size()), + .pStages = shader_stages.data(), + .pVertexInputState = &vertex_input_ci, + .pInputAssemblyState = &input_assembly_ci, + .pTessellationState = &tessellation_ci, + .pViewportState = &viewport_ci, + .pRasterizationState = &rasterization_ci, + .pMultisampleState = &multisample_ci, + .pDepthStencilState = &depth_stencil_ci, + .pColorBlendState = &color_blend_ci, + .pDynamicState = &dynamic_state_ci, + .layout = *layout, + .renderPass = renderpass, + .subpass = 0, + .basePipelineHandle = nullptr, + .basePipelineIndex = 0, + }; return device.GetLogical().CreateGraphicsPipeline(ci); } diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 380ed532b..7625871c2 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -332,23 +332,23 @@ private: if constexpr (has_extended_dynamic_state) { // With extended dynamic states we can specify the length and stride of a vertex buffer - // std::array<VkDeviceSize, N> sizes; + std::array<VkDeviceSize, N> sizes; std::array<u16, N> strides; - // std::copy(vertex.sizes.begin(), vertex.sizes.begin() + N, sizes.begin()); + std::copy(vertex.sizes.begin(), vertex.sizes.begin() + N, sizes.begin()); std::copy(vertex.strides.begin(), vertex.strides.begin() + N, strides.begin()); if constexpr (is_indexed) { scheduler.Record( - [buffers, offsets, strides, index = index](vk::CommandBuffer cmdbuf) { + [buffers, offsets, sizes, strides, index = index](vk::CommandBuffer cmdbuf) { cmdbuf.BindIndexBuffer(index.buffer, index.offset, index.type); cmdbuf.BindVertexBuffers2EXT(0, static_cast<u32>(N), buffers.data(), - offsets.data(), nullptr, + offsets.data(), sizes.data(), ExpandStrides(strides).data()); }); } else { - scheduler.Record([buffers, offsets, strides](vk::CommandBuffer cmdbuf) { + scheduler.Record([buffers, offsets, sizes, strides](vk::CommandBuffer cmdbuf) { cmdbuf.BindVertexBuffers2EXT(0, static_cast<u32>(N), buffers.data(), - offsets.data(), nullptr, + offsets.data(), sizes.data(), ExpandStrides(strides).data()); }); } diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index 0b2b2b8c4..921562c1f 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp @@ -343,8 +343,7 @@ std::size_t SurfaceParams::GetLayerSize(bool as_host_size, bool uncompressed) co size += GetInnerMipmapMemorySize(level, as_host_size, uncompressed); } if (is_tiled && is_layered) { - return Common::AlignBits(size, - Tegra::Texture::GetGOBSizeShift() + block_height + block_depth); + return Common::AlignBits(size, Tegra::Texture::GOB_SIZE_SHIFT + block_height + block_depth); } return size; } @@ -418,7 +417,7 @@ std::tuple<u32, u32, u32> SurfaceParams::GetBlockOffsetXYZ(u32 offset) const { const u32 block_size = GetBlockSize(); const u32 block_index = offset / block_size; const u32 gob_offset = offset % block_size; - const u32 gob_index = gob_offset / static_cast<u32>(Tegra::Texture::GetGOBSize()); + const u32 gob_index = gob_offset / static_cast<u32>(Tegra::Texture::GOB_SIZE); const u32 x_gob_pixels = 64U / GetBytesPerPixel(); const u32 x_block_pixels = x_gob_pixels << block_width; const u32 y_block_pixels = 8U << block_height; diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h index 24957df8d..118aa689e 100644 --- a/src/video_core/texture_cache/surface_params.h +++ b/src/video_core/texture_cache/surface_params.h @@ -204,7 +204,7 @@ public: static std::size_t AlignLayered(const std::size_t out_size, const u32 block_height, const u32 block_depth) { return Common::AlignBits(out_size, - Tegra::Texture::GetGOBSizeShift() + block_height + block_depth); + Tegra::Texture::GOB_SIZE_SHIFT + block_height + block_depth); } /// Converts a width from a type of surface into another. This helps represent the diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 548e4c3fe..98beabef1 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp @@ -6,6 +6,7 @@ #include <cstring> #include "common/alignment.h" #include "common/assert.h" +#include "common/bit_util.h" #include "video_core/gpu.h" #include "video_core/textures/decoders.h" #include "video_core/textures/texture.h" @@ -37,20 +38,10 @@ struct alignas(64) SwizzleTable { std::array<std::array<u16, M>, N> values{}; }; -constexpr u32 gob_size_x_shift = 6; -constexpr u32 gob_size_y_shift = 3; -constexpr u32 gob_size_z_shift = 0; -constexpr u32 gob_size_shift = gob_size_x_shift + gob_size_y_shift + gob_size_z_shift; +constexpr u32 FAST_SWIZZLE_ALIGN = 16; -constexpr u32 gob_size_x = 1U << gob_size_x_shift; -constexpr u32 gob_size_y = 1U << gob_size_y_shift; -constexpr u32 gob_size_z = 1U << gob_size_z_shift; -constexpr u32 gob_size = 1U << gob_size_shift; - -constexpr u32 fast_swizzle_align = 16; - -constexpr auto legacy_swizzle_table = SwizzleTable<gob_size_y, gob_size_x, gob_size_z>(); -constexpr auto fast_swizzle_table = SwizzleTable<gob_size_y, 4, fast_swizzle_align>(); +constexpr auto LEGACY_SWIZZLE_TABLE = SwizzleTable<GOB_SIZE_X, GOB_SIZE_X, GOB_SIZE_Z>(); +constexpr auto FAST_SWIZZLE_TABLE = SwizzleTable<GOB_SIZE_Y, 4, FAST_SWIZZLE_ALIGN>(); /** * This function manages ALL the GOBs(Group of Bytes) Inside a single block. @@ -69,17 +60,17 @@ void PreciseProcessBlock(u8* const swizzled_data, u8* const unswizzled_data, con u32 y_address = z_address; u32 pixel_base = layer_z * z + y_start * stride_x; for (u32 y = y_start; y < y_end; y++) { - const auto& table = legacy_swizzle_table[y % gob_size_y]; + const auto& table = LEGACY_SWIZZLE_TABLE[y % GOB_SIZE_Y]; for (u32 x = x_start; x < x_end; x++) { - const u32 swizzle_offset{y_address + table[x * bytes_per_pixel % gob_size_x]}; + const u32 swizzle_offset{y_address + table[x * bytes_per_pixel % GOB_SIZE_X]}; const u32 pixel_index{x * out_bytes_per_pixel + pixel_base}; data_ptrs[unswizzle] = swizzled_data + swizzle_offset; data_ptrs[!unswizzle] = unswizzled_data + pixel_index; std::memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel); } pixel_base += stride_x; - if ((y + 1) % gob_size_y == 0) - y_address += gob_size; + if ((y + 1) % GOB_SIZE_Y == 0) + y_address += GOB_SIZE; } z_address += xy_block_size; } @@ -104,18 +95,18 @@ void FastProcessBlock(u8* const swizzled_data, u8* const unswizzled_data, const u32 y_address = z_address; u32 pixel_base = layer_z * z + y_start * stride_x; for (u32 y = y_start; y < y_end; y++) { - const auto& table = fast_swizzle_table[y % gob_size_y]; - for (u32 xb = x_startb; xb < x_endb; xb += fast_swizzle_align) { - const u32 swizzle_offset{y_address + table[(xb / fast_swizzle_align) % 4]}; + const auto& table = FAST_SWIZZLE_TABLE[y % GOB_SIZE_Y]; + for (u32 xb = x_startb; xb < x_endb; xb += FAST_SWIZZLE_ALIGN) { + const u32 swizzle_offset{y_address + table[(xb / FAST_SWIZZLE_ALIGN) % 4]}; const u32 out_x = xb * out_bytes_per_pixel / bytes_per_pixel; const u32 pixel_index{out_x + pixel_base}; data_ptrs[unswizzle ? 1 : 0] = swizzled_data + swizzle_offset; data_ptrs[unswizzle ? 0 : 1] = unswizzled_data + pixel_index; - std::memcpy(data_ptrs[0], data_ptrs[1], fast_swizzle_align); + std::memcpy(data_ptrs[0], data_ptrs[1], FAST_SWIZZLE_ALIGN); } pixel_base += stride_x; - if ((y + 1) % gob_size_y == 0) - y_address += gob_size; + if ((y + 1) % GOB_SIZE_Y == 0) + y_address += GOB_SIZE; } z_address += xy_block_size; } @@ -138,9 +129,9 @@ void SwizzledData(u8* const swizzled_data, u8* const unswizzled_data, const bool auto div_ceil = [](const u32 x, const u32 y) { return ((x + y - 1) / y); }; const u32 stride_x = width * out_bytes_per_pixel; const u32 layer_z = height * stride_x; - const u32 gob_elements_x = gob_size_x / bytes_per_pixel; - constexpr u32 gob_elements_y = gob_size_y; - constexpr u32 gob_elements_z = gob_size_z; + const u32 gob_elements_x = GOB_SIZE_X / bytes_per_pixel; + constexpr u32 gob_elements_y = GOB_SIZE_Y; + constexpr u32 gob_elements_z = GOB_SIZE_Z; const u32 block_x_elements = gob_elements_x; const u32 block_y_elements = gob_elements_y * block_height; const u32 block_z_elements = gob_elements_z * block_depth; @@ -148,7 +139,7 @@ void SwizzledData(u8* const swizzled_data, u8* const unswizzled_data, const bool const u32 blocks_on_x = div_ceil(aligned_width, block_x_elements); const u32 blocks_on_y = div_ceil(height, block_y_elements); const u32 blocks_on_z = div_ceil(depth, block_z_elements); - const u32 xy_block_size = gob_size * block_height; + const u32 xy_block_size = GOB_SIZE * block_height; const u32 block_size = xy_block_size * block_depth; u32 tile_offset = 0; for (u32 zb = 0; zb < blocks_on_z; zb++) { @@ -182,7 +173,7 @@ void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel, bool unswizzle, u32 block_height, u32 block_depth, u32 width_spacing) { const u32 block_height_size{1U << block_height}; const u32 block_depth_size{1U << block_depth}; - if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % fast_swizzle_align == 0) { + if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % FAST_SWIZZLE_ALIGN == 0) { SwizzledData<true>(swizzled_data, unswizzled_data, unswizzle, width, height, depth, bytes_per_pixel, out_bytes_per_pixel, block_height_size, block_depth_size, width_spacing); @@ -259,25 +250,26 @@ std::vector<u8> UnswizzleTexture(u8* address, u32 tile_size_x, u32 tile_size_y, } void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width, - u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, + u32 bytes_per_pixel, u8* swizzled_data, const u8* unswizzled_data, u32 block_height_bit, u32 offset_x, u32 offset_y) { const u32 block_height = 1U << block_height_bit; - const u32 image_width_in_gobs{(swizzled_width * bytes_per_pixel + (gob_size_x - 1)) / - gob_size_x}; + const u32 image_width_in_gobs = + (swizzled_width * bytes_per_pixel + (GOB_SIZE_X - 1)) / GOB_SIZE_X; for (u32 line = 0; line < subrect_height; ++line) { const u32 dst_y = line + offset_y; const u32 gob_address_y = - (dst_y / (gob_size_y * block_height)) * gob_size * block_height * image_width_in_gobs + - ((dst_y % (gob_size_y * block_height)) / gob_size_y) * gob_size; - const auto& table = legacy_swizzle_table[dst_y % gob_size_y]; + (dst_y / (GOB_SIZE_Y * block_height)) * GOB_SIZE * block_height * image_width_in_gobs + + ((dst_y % (GOB_SIZE_Y * block_height)) / GOB_SIZE_Y) * GOB_SIZE; + const auto& table = LEGACY_SWIZZLE_TABLE[dst_y % GOB_SIZE_Y]; for (u32 x = 0; x < subrect_width; ++x) { const u32 dst_x = x + offset_x; const u32 gob_address = - gob_address_y + (dst_x * bytes_per_pixel / gob_size_x) * gob_size * block_height; - const u32 swizzled_offset = gob_address + table[(dst_x * bytes_per_pixel) % gob_size_x]; - u8* source_line = unswizzled_data + line * source_pitch + x * bytes_per_pixel; - u8* dest_addr = swizzled_data + swizzled_offset; + gob_address_y + (dst_x * bytes_per_pixel / GOB_SIZE_X) * GOB_SIZE * block_height; + const u32 swizzled_offset = gob_address + table[(dst_x * bytes_per_pixel) % GOB_SIZE_X]; + const u32 unswizzled_offset = line * source_pitch + x * bytes_per_pixel; + const u8* const source_line = unswizzled_data + unswizzled_offset; + u8* const dest_addr = swizzled_data + swizzled_offset; std::memcpy(dest_addr, source_line, bytes_per_pixel); } } @@ -289,14 +281,15 @@ void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 const u32 block_height = 1U << block_height_bit; for (u32 line = 0; line < subrect_height; ++line) { const u32 y2 = line + offset_y; - const u32 gob_address_y = (y2 / (gob_size_y * block_height)) * gob_size * block_height + - ((y2 % (gob_size_y * block_height)) / gob_size_y) * gob_size; - const auto& table = legacy_swizzle_table[y2 % gob_size_y]; + const u32 gob_address_y = (y2 / (GOB_SIZE_Y * block_height)) * GOB_SIZE * block_height + + ((y2 % (GOB_SIZE_Y * block_height)) / GOB_SIZE_Y) * GOB_SIZE; + const auto& table = LEGACY_SWIZZLE_TABLE[y2 % GOB_SIZE_Y]; for (u32 x = 0; x < subrect_width; ++x) { const u32 x2 = (x + offset_x) * bytes_per_pixel; - const u32 gob_address = gob_address_y + (x2 / gob_size_x) * gob_size * block_height; - const u32 swizzled_offset = gob_address + table[x2 % gob_size_x]; - u8* dest_line = unswizzled_data + line * dest_pitch + x * bytes_per_pixel; + const u32 gob_address = gob_address_y + (x2 / GOB_SIZE_X) * GOB_SIZE * block_height; + const u32 swizzled_offset = gob_address + table[x2 % GOB_SIZE_X]; + const u32 unswizzled_offset = line * dest_pitch + x * bytes_per_pixel; + u8* dest_line = unswizzled_data + unswizzled_offset; u8* source_addr = swizzled_data + swizzled_offset; std::memcpy(dest_line, source_addr, bytes_per_pixel); @@ -304,21 +297,48 @@ void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 } } +void SwizzleSliceToVoxel(u32 line_length_in, u32 line_count, u32 pitch, u32 width, u32 height, + u32 bytes_per_pixel, u32 block_height, u32 block_depth, u32 origin_x, + u32 origin_y, u8* output, const u8* input) { + UNIMPLEMENTED_IF(origin_x > 0); + UNIMPLEMENTED_IF(origin_y > 0); + + const u32 stride = width * bytes_per_pixel; + const u32 gobs_in_x = (stride + GOB_SIZE_X - 1) / GOB_SIZE_X; + const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height + block_depth); + + const u32 block_height_mask = (1U << block_height) - 1; + const u32 x_shift = Common::CountTrailingZeroes32(GOB_SIZE << (block_height + block_depth)); + + for (u32 line = 0; line < line_count; ++line) { + const auto& table = LEGACY_SWIZZLE_TABLE[line % GOB_SIZE_Y]; + const u32 block_y = line / GOB_SIZE_Y; + const u32 dst_offset_y = + (block_y >> block_height) * block_size + (block_y & block_height_mask) * GOB_SIZE; + for (u32 x = 0; x < line_length_in; ++x) { + const u32 dst_offset = + ((x / GOB_SIZE_X) << x_shift) + dst_offset_y + table[x % GOB_SIZE_X]; + const u32 src_offset = x * bytes_per_pixel + line * pitch; + std::memcpy(output + dst_offset, input + src_offset, bytes_per_pixel); + } + } +} + void SwizzleKepler(const u32 width, const u32 height, const u32 dst_x, const u32 dst_y, const u32 block_height_bit, const std::size_t copy_size, const u8* source_data, u8* swizzle_data) { const u32 block_height = 1U << block_height_bit; - const u32 image_width_in_gobs{(width + gob_size_x - 1) / gob_size_x}; + const u32 image_width_in_gobs{(width + GOB_SIZE_X - 1) / GOB_SIZE_X}; std::size_t count = 0; for (std::size_t y = dst_y; y < height && count < copy_size; ++y) { const std::size_t gob_address_y = - (y / (gob_size_y * block_height)) * gob_size * block_height * image_width_in_gobs + - ((y % (gob_size_y * block_height)) / gob_size_y) * gob_size; - const auto& table = legacy_swizzle_table[y % gob_size_y]; + (y / (GOB_SIZE_Y * block_height)) * GOB_SIZE * block_height * image_width_in_gobs + + ((y % (GOB_SIZE_Y * block_height)) / GOB_SIZE_Y) * GOB_SIZE; + const auto& table = LEGACY_SWIZZLE_TABLE[y % GOB_SIZE_Y]; for (std::size_t x = dst_x; x < width && count < copy_size; ++x) { const std::size_t gob_address = - gob_address_y + (x / gob_size_x) * gob_size * block_height; - const std::size_t swizzled_offset = gob_address + table[x % gob_size_x]; + gob_address_y + (x / GOB_SIZE_X) * GOB_SIZE * block_height; + const std::size_t swizzled_offset = gob_address + table[x % GOB_SIZE_X]; const u8* source_line = source_data + count; u8* dest_addr = swizzle_data + swizzled_offset; count++; @@ -373,9 +393,9 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth, u32 block_height, u32 block_depth) { if (tiled) { - const u32 aligned_width = Common::AlignBits(width * bytes_per_pixel, gob_size_x_shift); - const u32 aligned_height = Common::AlignBits(height, gob_size_y_shift + block_height); - const u32 aligned_depth = Common::AlignBits(depth, gob_size_z_shift + block_depth); + const u32 aligned_width = Common::AlignBits(width * bytes_per_pixel, GOB_SIZE_X_SHIFT); + const u32 aligned_height = Common::AlignBits(height, GOB_SIZE_Y_SHIFT + block_height); + const u32 aligned_depth = Common::AlignBits(depth, GOB_SIZE_Z_SHIFT + block_depth); return aligned_width * aligned_height * aligned_depth; } else { return width * height * depth * bytes_per_pixel; @@ -386,14 +406,14 @@ u64 GetGOBOffset(u32 width, u32 height, u32 dst_x, u32 dst_y, u32 block_height, u32 bytes_per_pixel) { auto div_ceil = [](const u32 x, const u32 y) { return ((x + y - 1) / y); }; const u32 gobs_in_block = 1 << block_height; - const u32 y_blocks = gob_size_y << block_height; - const u32 x_per_gob = gob_size_x / bytes_per_pixel; + const u32 y_blocks = GOB_SIZE_Y << block_height; + const u32 x_per_gob = GOB_SIZE_X / bytes_per_pixel; const u32 x_blocks = div_ceil(width, x_per_gob); - const u32 block_size = gob_size * gobs_in_block; + const u32 block_size = GOB_SIZE * gobs_in_block; const u32 stride = block_size * x_blocks; const u32 base = (dst_y / y_blocks) * stride + (dst_x / x_per_gob) * block_size; const u32 relative_y = dst_y % y_blocks; - return base + (relative_y / gob_size_y) * gob_size; + return base + (relative_y / GOB_SIZE_Y) * GOB_SIZE; } } // namespace Tegra::Texture diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h index 06f3ebf87..232b696b3 100644 --- a/src/video_core/textures/decoders.h +++ b/src/video_core/textures/decoders.h @@ -10,15 +10,15 @@ namespace Tegra::Texture { -// GOBSize constant. Calculated by 64 bytes in x multiplied by 8 y coords, represents -// an small rect of (64/bytes_per_pixel)X8. -inline std::size_t GetGOBSize() { - return 512; -} +constexpr u32 GOB_SIZE_X = 64; +constexpr u32 GOB_SIZE_Y = 8; +constexpr u32 GOB_SIZE_Z = 1; +constexpr u32 GOB_SIZE = GOB_SIZE_X * GOB_SIZE_Y * GOB_SIZE_Z; -inline std::size_t GetGOBSizeShift() { - return 9; -} +constexpr std::size_t GOB_SIZE_X_SHIFT = 6; +constexpr std::size_t GOB_SIZE_Y_SHIFT = 3; +constexpr std::size_t GOB_SIZE_Z_SHIFT = 0; +constexpr std::size_t GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT + GOB_SIZE_Z_SHIFT; /// Unswizzles a swizzled texture without changing its format. void UnswizzleTexture(u8* unswizzled_data, u8* address, u32 tile_size_x, u32 tile_size_y, @@ -48,14 +48,32 @@ std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height /// Copies an untiled subrectangle into a tiled surface. void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width, - u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, u32 block_height, - u32 offset_x, u32 offset_y); + u32 bytes_per_pixel, u8* swizzled_data, const u8* unswizzled_data, + u32 block_height_bit, u32 offset_x, u32 offset_y); /// Copies a tiled subrectangle into a linear surface. void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 swizzled_width, u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, u32 block_height, u32 offset_x, u32 offset_y); +/// @brief Swizzles a 2D array of pixels into a 3D texture +/// @param line_length_in Number of pixels per line +/// @param line_count Number of lines +/// @param pitch Number of bytes per line +/// @param width Width of the swizzled texture +/// @param height Height of the swizzled texture +/// @param bytes_per_pixel Number of bytes used per pixel +/// @param block_height Block height shift +/// @param block_depth Block depth shift +/// @param origin_x Column offset in pixels of the swizzled texture +/// @param origin_y Row offset in pixels of the swizzled texture +/// @param output Pointer to the pixels of the swizzled texture +/// @param input Pointer to the 2D array of pixels used as input +/// @pre input and output points to an array large enough to hold the number of bytes used +void SwizzleSliceToVoxel(u32 line_length_in, u32 line_count, u32 pitch, u32 width, u32 height, + u32 bytes_per_pixel, u32 block_height, u32 block_depth, u32 origin_x, + u32 origin_y, u8* output, const u8* input); + void SwizzleKepler(u32 width, u32 height, u32 dst_x, u32 dst_y, u32 block_height, std::size_t copy_size, const u8* source_data, u8* swizzle_data); diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 6b25a7fa0..a862b2610 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -30,6 +30,12 @@ add_executable(yuzu configuration/configure_audio.cpp configuration/configure_audio.h configuration/configure_audio.ui + configuration/configure_cpu.cpp + configuration/configure_cpu.h + configuration/configure_cpu.ui + configuration/configure_cpu_debug.cpp + configuration/configure_cpu_debug.h + configuration/configure_cpu_debug.ui configuration/configure_debug.cpp configuration/configure_debug.h configuration/configure_debug.ui @@ -98,11 +104,13 @@ add_executable(yuzu game_list_p.h game_list_worker.cpp game_list_worker.h + hotkeys.cpp + hotkeys.h + install_dialog.cpp + install_dialog.h loading_screen.cpp loading_screen.h loading_screen.ui - hotkeys.cpp - hotkeys.h main.cpp main.h main.ui diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 1b2b1b2bb..d25b99a32 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -505,22 +505,6 @@ void Config::ReadDataStorageValues() { ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool(); Settings::values.gamecard_path = ReadSetting(QStringLiteral("gamecard_path"), QStringLiteral("")).toString().toStdString(); - Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>( - ReadSetting(QStringLiteral("nand_total_size"), - QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDTotalSize::S29_1GB))) - .toULongLong()); - Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>( - ReadSetting(QStringLiteral("nand_user_size"), - QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDUserSize::S26GB))) - .toULongLong()); - Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>( - ReadSetting(QStringLiteral("nand_system_size"), - QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDSystemSize::S2_5GB))) - .toULongLong()); - Settings::values.sdmc_size = static_cast<Settings::SDMCSize>( - ReadSetting(QStringLiteral("sdmc_size"), - QVariant::fromValue<u64>(static_cast<u64>(Settings::SDMCSize::S16GB))) - .toULongLong()); qt_config->endGroup(); } @@ -540,8 +524,6 @@ void Config::ReadDebuggingValues() { Settings::values.reporting_services = ReadSetting(QStringLiteral("reporting_services"), false).toBool(); Settings::values.quest_flag = ReadSetting(QStringLiteral("quest_flag"), false).toBool(); - Settings::values.disable_cpu_opt = - ReadSetting(QStringLiteral("disable_cpu_opt"), false).toBool(); Settings::values.disable_macro_jit = ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool(); @@ -633,6 +615,34 @@ void Config::ReadPathValues() { qt_config->endGroup(); } +void Config::ReadCpuValues() { + qt_config->beginGroup(QStringLiteral("Cpu")); + + if (global) { + Settings::values.cpu_accuracy = static_cast<Settings::CPUAccuracy>( + ReadSetting(QStringLiteral("cpu_accuracy"), 0).toInt()); + + Settings::values.cpuopt_page_tables = + ReadSetting(QStringLiteral("cpuopt_page_tables"), true).toBool(); + Settings::values.cpuopt_block_linking = + ReadSetting(QStringLiteral("cpuopt_block_linking"), true).toBool(); + Settings::values.cpuopt_return_stack_buffer = + ReadSetting(QStringLiteral("cpuopt_return_stack_buffer"), true).toBool(); + Settings::values.cpuopt_fast_dispatcher = + ReadSetting(QStringLiteral("cpuopt_fast_dispatcher"), true).toBool(); + Settings::values.cpuopt_context_elimination = + ReadSetting(QStringLiteral("cpuopt_context_elimination"), true).toBool(); + Settings::values.cpuopt_const_prop = + ReadSetting(QStringLiteral("cpuopt_const_prop"), true).toBool(); + Settings::values.cpuopt_misc_ir = + ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool(); + Settings::values.cpuopt_reduce_misalign_checks = + ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool(); + } + + qt_config->endGroup(); +} + void Config::ReadRendererValues() { qt_config->beginGroup(QStringLiteral("Renderer")); @@ -829,6 +839,7 @@ void Config::ReadValues() { ReadMiscellaneousValues(); } ReadCoreValues(); + ReadCpuValues(); ReadRendererValues(); ReadAudioValues(); ReadSystemValues(); @@ -929,6 +940,7 @@ void Config::SaveValues() { SaveMiscellaneousValues(); } SaveCoreValues(); + SaveCpuValues(); SaveRendererValues(); SaveAudioValues(); SaveSystemValues(); @@ -1006,18 +1018,7 @@ void Config::SaveDataStorageValues() { false); WriteSetting(QStringLiteral("gamecard_path"), QString::fromStdString(Settings::values.gamecard_path), QStringLiteral("")); - WriteSetting(QStringLiteral("nand_total_size"), - QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_total_size)), - QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDTotalSize::S29_1GB))); - WriteSetting(QStringLiteral("nand_user_size"), - QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_user_size)), - QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDUserSize::S26GB))); - WriteSetting(QStringLiteral("nand_system_size"), - QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_system_size)), - QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDSystemSize::S2_5GB))); - WriteSetting(QStringLiteral("sdmc_size"), - QVariant::fromValue<u64>(static_cast<u64>(Settings::values.sdmc_size)), - QVariant::fromValue<u64>(static_cast<u64>(Settings::SDMCSize::S16GB))); + qt_config->endGroup(); } @@ -1033,7 +1034,6 @@ void Config::SaveDebuggingValues() { WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false); WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false); WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false); - WriteSetting(QStringLiteral("disable_cpu_opt"), Settings::values.disable_cpu_opt, false); WriteSetting(QStringLiteral("disable_macro_jit"), Settings::values.disable_macro_jit, false); qt_config->endGroup(); @@ -1097,6 +1097,32 @@ void Config::SavePathValues() { qt_config->endGroup(); } +void Config::SaveCpuValues() { + qt_config->beginGroup(QStringLiteral("Cpu")); + + if (global) { + WriteSetting(QStringLiteral("cpu_accuracy"), + static_cast<int>(Settings::values.cpu_accuracy), 0); + + WriteSetting(QStringLiteral("cpuopt_page_tables"), Settings::values.cpuopt_page_tables, + true); + WriteSetting(QStringLiteral("cpuopt_block_linking"), Settings::values.cpuopt_block_linking, + true); + WriteSetting(QStringLiteral("cpuopt_return_stack_buffer"), + Settings::values.cpuopt_return_stack_buffer, true); + WriteSetting(QStringLiteral("cpuopt_fast_dispatcher"), + Settings::values.cpuopt_fast_dispatcher, true); + WriteSetting(QStringLiteral("cpuopt_context_elimination"), + Settings::values.cpuopt_context_elimination, true); + WriteSetting(QStringLiteral("cpuopt_const_prop"), Settings::values.cpuopt_const_prop, true); + WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true); + WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), + Settings::values.cpuopt_reduce_misalign_checks, true); + } + + qt_config->endGroup(); +} + void Config::SaveRendererValues() { qt_config->beginGroup(QStringLiteral("Renderer")); @@ -1342,11 +1368,13 @@ void Config::WriteSettingGlobal(const QString& name, const QVariant& value, bool void Config::Reload() { ReadValues(); + Settings::Sanitize(); // To apply default value changes SaveValues(); Settings::Apply(); } void Config::Save() { + Settings::Sanitize(); SaveValues(); } diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index 681f0bca5..8e815f829 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -49,6 +49,7 @@ private: void ReadDisabledAddOnValues(); void ReadMiscellaneousValues(); void ReadPathValues(); + void ReadCpuValues(); void ReadRendererValues(); void ReadShortcutValues(); void ReadSystemValues(); @@ -73,6 +74,7 @@ private: void SaveDisabledAddOnValues(); void SaveMiscellaneousValues(); void SavePathValues(); + void SaveCpuValues(); void SaveRendererValues(); void SaveShortcutValues(); void SaveSystemValues(); diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui index 9aec1bd09..5f5d8e571 100644 --- a/src/yuzu/configuration/configure.ui +++ b/src/yuzu/configuration/configure.ui @@ -78,6 +78,16 @@ <string>Hotkeys</string> </attribute> </widget> + <widget class="ConfigureCpu" name="cpuTab"> + <attribute name="title"> + <string>CPU</string> + </attribute> + </widget> + <widget class="ConfigureCpuDebug" name="cpuDebugTab"> + <attribute name="title"> + <string>Debug</string> + </attribute> + </widget> <widget class="ConfigureGraphics" name="graphicsTab"> <attribute name="title"> <string>Graphics</string> @@ -159,6 +169,18 @@ <container>1</container> </customwidget> <customwidget> + <class>ConfigureCpu</class> + <extends>QWidget</extends> + <header>configuration/configure_cpu.h</header> + <container>1</container> + </customwidget> + <customwidget> + <class>ConfigureCpuDebug</class> + <extends>QWidget</extends> + <header>configuration/configure_cpu_debug.h</header> + <container>1</container> + </customwidget> + <customwidget> <class>ConfigureGraphics</class> <extends>QWidget</extends> <header>configuration/configure_graphics.h</header> diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp new file mode 100644 index 000000000..7493e5ffb --- /dev/null +++ b/src/yuzu/configuration/configure_cpu.cpp @@ -0,0 +1,61 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <QComboBox> +#include <QMessageBox> + +#include "common/common_types.h" +#include "common/logging/log.h" +#include "core/core.h" +#include "core/settings.h" +#include "ui_configure_cpu.h" +#include "yuzu/configuration/configure_cpu.h" + +ConfigureCpu::ConfigureCpu(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureCpu) { + ui->setupUi(this); + + SetConfiguration(); + + connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this, + &ConfigureCpu::AccuracyUpdated); +} + +ConfigureCpu::~ConfigureCpu() = default; + +void ConfigureCpu::SetConfiguration() { + const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); + + ui->accuracy->setEnabled(runtime_lock); + ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy)); +} + +void ConfigureCpu::AccuracyUpdated(int index) { + if (static_cast<Settings::CPUAccuracy>(index) == Settings::CPUAccuracy::DebugMode) { + const auto result = QMessageBox::warning(this, tr("Setting CPU to Debug Mode"), + tr("CPU Debug Mode is only intended for developer " + "use. Are you sure you want to enable this?"), + QMessageBox::Yes | QMessageBox::No); + if (result == QMessageBox::No) { + ui->accuracy->setCurrentIndex(static_cast<int>(Settings::CPUAccuracy::Accurate)); + return; + } + } +} + +void ConfigureCpu::ApplyConfiguration() { + Settings::values.cpu_accuracy = + static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex()); +} + +void ConfigureCpu::changeEvent(QEvent* event) { + if (event->type() == QEvent::LanguageChange) { + RetranslateUI(); + } + + QWidget::changeEvent(event); +} + +void ConfigureCpu::RetranslateUI() { + ui->retranslateUi(this); +} diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h new file mode 100644 index 000000000..e4741d3a4 --- /dev/null +++ b/src/yuzu/configuration/configure_cpu.h @@ -0,0 +1,33 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <QWidget> +#include "core/settings.h" + +namespace Ui { +class ConfigureCpu; +} + +class ConfigureCpu : public QWidget { + Q_OBJECT + +public: + explicit ConfigureCpu(QWidget* parent = nullptr); + ~ConfigureCpu() override; + + void ApplyConfiguration(); + +private: + void changeEvent(QEvent* event) override; + void RetranslateUI(); + + void AccuracyUpdated(int index); + + void SetConfiguration(); + + std::unique_ptr<Ui::ConfigureCpu> ui; +}; diff --git a/src/yuzu/configuration/configure_cpu.ui b/src/yuzu/configuration/configure_cpu.ui new file mode 100644 index 000000000..bf6ea79bb --- /dev/null +++ b/src/yuzu/configuration/configure_cpu.ui @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ConfigureCpu</class> + <widget class="QWidget" name="ConfigureCpu"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>321</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout"> + <item> + <layout class="QVBoxLayout"> + <item> + <widget class="QGroupBox"> + <property name="title"> + <string>General</string> + </property> + <layout class="QVBoxLayout"> + <item> + <layout class="QHBoxLayout"> + <item> + <widget class="QLabel"> + <property name="text"> + <string>Accuracy:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="accuracy"> + <item> + <property name="text"> + <string>Accurate</string> + </property> + </item> + <item> + <property name="text"> + <string>Enable Debug Mode</string> + </property> + </item> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QLabel"> + <property name="wordWrap"> + <bool>1</bool> + </property> + <property name="text"> + <string>We recommend setting accuracy to "Accurate".</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="label_disable_info"> + <property name="text"> + <string>CPU settings are available only when game is not running.</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/yuzu/configuration/configure_cpu_debug.cpp b/src/yuzu/configuration/configure_cpu_debug.cpp new file mode 100644 index 000000000..3385b2cf6 --- /dev/null +++ b/src/yuzu/configuration/configure_cpu_debug.cpp @@ -0,0 +1,65 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <QComboBox> + +#include "common/common_types.h" +#include "common/logging/log.h" +#include "core/core.h" +#include "core/settings.h" +#include "ui_configure_cpu_debug.h" +#include "yuzu/configuration/configure_cpu_debug.h" + +ConfigureCpuDebug::ConfigureCpuDebug(QWidget* parent) + : QWidget(parent), ui(new Ui::ConfigureCpuDebug) { + ui->setupUi(this); + + SetConfiguration(); +} + +ConfigureCpuDebug::~ConfigureCpuDebug() = default; + +void ConfigureCpuDebug::SetConfiguration() { + const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); + + ui->cpuopt_page_tables->setEnabled(runtime_lock); + ui->cpuopt_page_tables->setChecked(Settings::values.cpuopt_page_tables); + ui->cpuopt_block_linking->setEnabled(runtime_lock); + ui->cpuopt_block_linking->setChecked(Settings::values.cpuopt_block_linking); + ui->cpuopt_return_stack_buffer->setEnabled(runtime_lock); + ui->cpuopt_return_stack_buffer->setChecked(Settings::values.cpuopt_return_stack_buffer); + ui->cpuopt_fast_dispatcher->setEnabled(runtime_lock); + ui->cpuopt_fast_dispatcher->setChecked(Settings::values.cpuopt_fast_dispatcher); + ui->cpuopt_context_elimination->setEnabled(runtime_lock); + ui->cpuopt_context_elimination->setChecked(Settings::values.cpuopt_context_elimination); + ui->cpuopt_const_prop->setEnabled(runtime_lock); + ui->cpuopt_const_prop->setChecked(Settings::values.cpuopt_const_prop); + ui->cpuopt_misc_ir->setEnabled(runtime_lock); + ui->cpuopt_misc_ir->setChecked(Settings::values.cpuopt_misc_ir); + ui->cpuopt_reduce_misalign_checks->setEnabled(runtime_lock); + ui->cpuopt_reduce_misalign_checks->setChecked(Settings::values.cpuopt_reduce_misalign_checks); +} + +void ConfigureCpuDebug::ApplyConfiguration() { + Settings::values.cpuopt_page_tables = ui->cpuopt_page_tables->isChecked(); + Settings::values.cpuopt_block_linking = ui->cpuopt_block_linking->isChecked(); + Settings::values.cpuopt_return_stack_buffer = ui->cpuopt_return_stack_buffer->isChecked(); + Settings::values.cpuopt_fast_dispatcher = ui->cpuopt_fast_dispatcher->isChecked(); + Settings::values.cpuopt_context_elimination = ui->cpuopt_context_elimination->isChecked(); + Settings::values.cpuopt_const_prop = ui->cpuopt_const_prop->isChecked(); + Settings::values.cpuopt_misc_ir = ui->cpuopt_misc_ir->isChecked(); + Settings::values.cpuopt_reduce_misalign_checks = ui->cpuopt_reduce_misalign_checks->isChecked(); +} + +void ConfigureCpuDebug::changeEvent(QEvent* event) { + if (event->type() == QEvent::LanguageChange) { + RetranslateUI(); + } + + QWidget::changeEvent(event); +} + +void ConfigureCpuDebug::RetranslateUI() { + ui->retranslateUi(this); +} diff --git a/src/yuzu/configuration/configure_cpu_debug.h b/src/yuzu/configuration/configure_cpu_debug.h new file mode 100644 index 000000000..c9941ef3b --- /dev/null +++ b/src/yuzu/configuration/configure_cpu_debug.h @@ -0,0 +1,31 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <QWidget> +#include "core/settings.h" + +namespace Ui { +class ConfigureCpuDebug; +} + +class ConfigureCpuDebug : public QWidget { + Q_OBJECT + +public: + explicit ConfigureCpuDebug(QWidget* parent = nullptr); + ~ConfigureCpuDebug() override; + + void ApplyConfiguration(); + +private: + void changeEvent(QEvent* event) override; + void RetranslateUI(); + + void SetConfiguration(); + + std::unique_ptr<Ui::ConfigureCpuDebug> ui; +}; diff --git a/src/yuzu/configuration/configure_cpu_debug.ui b/src/yuzu/configuration/configure_cpu_debug.ui new file mode 100644 index 000000000..a90dc64fe --- /dev/null +++ b/src/yuzu/configuration/configure_cpu_debug.ui @@ -0,0 +1,174 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ConfigureCpuDebug</class> + <widget class="QWidget" name="ConfigureCpuDebug"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>321</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout"> + <item> + <layout class="QVBoxLayout"> + <item> + <widget class="QGroupBox"> + <property name="title"> + <string>Toggle CPU Optimizations</string> + </property> + <layout class="QVBoxLayout"> + <item> + <widget class="QLabel"> + <property name="wordWrap"> + <bool>1</bool> + </property> + <property name="text"> + <string> + <div> + <b>For debugging only.</b> + <br> + If you're not sure what these do, keep all of these enabled. + <br> + These settings only take effect when CPU Accuracy is "Debug Mode". + </div> + </string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="cpuopt_page_tables"> + <property name="text"> + <string>Enable inline page tables</string> + </property> + <property name="toolTip"> + <string> + <div style="white-space: nowrap">This optimization speeds up memory accesses by the guest program.</div> + <div style="white-space: nowrap">Enabling it inlines accesses to PageTable::pointers into emitted code.</div> + <div style="white-space: nowrap">Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.</div> + </string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="cpuopt_block_linking"> + <property name="text"> + <string>Enable block linking</string> + </property> + <property name="toolTip"> + <string> + <div>This optimization avoids dispatcher lookups by allowing emitted basic blocks to jump directly to other basic blocks if the destination PC is static.</div> + </string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="cpuopt_return_stack_buffer"> + <property name="text"> + <string>Enable return stack buffer</string> + </property> + <property name="toolTip"> + <string> + <div>This optimization avoids dispatcher lookups by keeping track potential return addresses of BL instructions. This approximates what happens with a return stack buffer on a real CPU.</div> + </string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="cpuopt_fast_dispatcher"> + <property name="text"> + <string>Enable fast dispatcher</string> + </property> + <property name="toolTip"> + <string> + <div>Enable a two-tiered dispatch system. A faster dispatcher written in assembly has a small MRU cache of jump destinations is used first. If that fails, dispatch falls back to the slower C++ dispatcher.</div> + </string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="cpuopt_context_elimination"> + <property name="text"> + <string>Enable context elimination</string> + </property> + <property name="toolTip"> + <string> + <div>Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.</div> + </string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="cpuopt_const_prop"> + <property name="text"> + <string>Enable constant propagation</string> + </property> + <property name="toolTip"> + <string> + <div>Enables IR optimizations that involve constant propagation.</div> + </string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="cpuopt_misc_ir"> + <property name="text"> + <string>Enable miscellaneous optimizations</string> + </property> + <property name="toolTip"> + <string> + <div>Enables miscellaneous IR optimizations.</div> + </string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="cpuopt_reduce_misalign_checks"> + <property name="text"> + <string>Enable misalignment check reduction</string> + </property> + <property name="toolTip"> + <string> + <div style="white-space: nowrap">When enabled, a misalignment is only triggered when an access crosses a page boundary.</div> + <div style="white-space: nowrap">When disabled, a misalignment is triggered on all misaligned accesses.</div> + </string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="label_disable_info"> + <property name="text"> + <string>CPU settings are available only when game is not running.</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index 2c77441fd..d0e71dd60 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp @@ -36,7 +36,6 @@ void ConfigureDebug::SetConfiguration() { ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args)); ui->reporting_services->setChecked(Settings::values.reporting_services); ui->quest_flag->setChecked(Settings::values.quest_flag); - ui->disable_cpu_opt->setChecked(Settings::values.disable_cpu_opt); ui->enable_graphics_debugging->setEnabled(!Core::System::GetInstance().IsPoweredOn()); ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug); ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); @@ -51,7 +50,6 @@ void ConfigureDebug::ApplyConfiguration() { Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); Settings::values.reporting_services = ui->reporting_services->isChecked(); Settings::values.quest_flag = ui->quest_flag->isChecked(); - Settings::values.disable_cpu_opt = ui->disable_cpu_opt->isChecked(); Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); Debugger::ToggleConsole(); diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index 46f0208c6..272bdd6b8 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui @@ -228,13 +228,6 @@ </property> </widget> </item> - <item> - <widget class="QCheckBox" name="disable_cpu_opt"> - <property name="text"> - <string>Disable CPU JIT optimizations</string> - </property> - </widget> - </item> </layout> </widget> </item> diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 5918e9972..a5afb354f 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -42,6 +42,8 @@ void ConfigureDialog::ApplyConfiguration() { ui->filesystemTab->applyConfiguration(); ui->inputTab->ApplyConfiguration(); ui->hotkeysTab->ApplyConfiguration(registry); + ui->cpuTab->ApplyConfiguration(); + ui->cpuDebugTab->ApplyConfiguration(); ui->graphicsTab->ApplyConfiguration(); ui->graphicsAdvancedTab->ApplyConfiguration(); ui->audioTab->ApplyConfiguration(); @@ -76,9 +78,10 @@ void ConfigureDialog::RetranslateUI() { Q_DECLARE_METATYPE(QList<QWidget*>); void ConfigureDialog::PopulateSelectionList() { - const std::array<std::pair<QString, QList<QWidget*>>, 5> items{ + const std::array<std::pair<QString, QList<QWidget*>>, 6> items{ {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->uiTab}}, {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}}, + {tr("CPU"), {ui->cpuTab, ui->cpuDebugTab}}, {tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}}, {tr("Audio"), {ui->audioTab}}, {tr("Controls"), {ui->inputTab, ui->hotkeysTab}}}, @@ -107,6 +110,8 @@ void ConfigureDialog::UpdateVisibleTabs() { {ui->profileManagerTab, tr("Profiles")}, {ui->inputTab, tr("Input")}, {ui->hotkeysTab, tr("Hotkeys")}, + {ui->cpuTab, tr("CPU")}, + {ui->cpuDebugTab, tr("Debug")}, {ui->graphicsTab, tr("Graphics")}, {ui->graphicsAdvancedTab, tr("Advanced")}, {ui->audioTab, tr("Audio")}, diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp index 835ee821c..a089f5733 100644 --- a/src/yuzu/configuration/configure_filesystem.cpp +++ b/src/yuzu/configuration/configure_filesystem.cpp @@ -11,19 +11,6 @@ #include "yuzu/configuration/configure_filesystem.h" #include "yuzu/uisettings.h" -namespace { - -template <typename T> -void SetComboBoxFromData(QComboBox* combo_box, T data) { - const auto index = combo_box->findData(QVariant::fromValue(static_cast<u64>(data))); - if (index >= combo_box->count() || index < 0) - return; - - combo_box->setCurrentIndex(index); -} - -} // Anonymous namespace - ConfigureFilesystem::ConfigureFilesystem(QWidget* parent) : QWidget(parent), ui(std::make_unique<Ui::ConfigureFilesystem>()) { ui->setupUi(this); @@ -73,11 +60,6 @@ void ConfigureFilesystem::setConfiguration() { ui->cache_game_list->setChecked(UISettings::values.cache_game_list); - SetComboBoxFromData(ui->nand_size, Settings::values.nand_total_size); - SetComboBoxFromData(ui->usrnand_size, Settings::values.nand_user_size); - SetComboBoxFromData(ui->sysnand_size, Settings::values.nand_system_size); - SetComboBoxFromData(ui->sdmc_size, Settings::values.sdmc_size); - UpdateEnabledControls(); } @@ -98,15 +80,6 @@ void ConfigureFilesystem::applyConfiguration() { Settings::values.dump_nso = ui->dump_nso->isChecked(); UISettings::values.cache_game_list = ui->cache_game_list->isChecked(); - - Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>( - ui->nand_size->itemData(ui->nand_size->currentIndex()).toULongLong()); - Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>( - ui->nand_size->itemData(ui->sysnand_size->currentIndex()).toULongLong()); - Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>( - ui->nand_size->itemData(ui->usrnand_size->currentIndex()).toULongLong()); - Settings::values.sdmc_size = static_cast<Settings::SDMCSize>( - ui->nand_size->itemData(ui->sdmc_size->currentIndex()).toULongLong()); } void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit) { diff --git a/src/yuzu/configuration/configure_filesystem.ui b/src/yuzu/configuration/configure_filesystem.ui index 58cd07f52..84bea0600 100644 --- a/src/yuzu/configuration/configure_filesystem.ui +++ b/src/yuzu/configuration/configure_filesystem.ui @@ -116,127 +116,6 @@ </widget> </item> <item> - <widget class="QGroupBox" name="groupBox_3"> - <property name="title"> - <string>Storage Sizes</string> - </property> - <layout class="QGridLayout" name="gridLayout_3"> - <item row="3" column="0"> - <widget class="QLabel" name="label_5"> - <property name="text"> - <string>SD Card</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string>System NAND</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QComboBox" name="sysnand_size"> - <item> - <property name="text"> - <string>2.5 GB</string> - </property> - </item> - </widget> - </item> - <item row="3" column="1"> - <widget class="QComboBox" name="sdmc_size"> - <property name="currentText"> - <string>32 GB</string> - </property> - <item> - <property name="text"> - <string>1 GB</string> - </property> - </item> - <item> - <property name="text"> - <string>2 GB</string> - </property> - </item> - <item> - <property name="text"> - <string>4 GB</string> - </property> - </item> - <item> - <property name="text"> - <string>8 GB</string> - </property> - </item> - <item> - <property name="text"> - <string>16 GB</string> - </property> - </item> - <item> - <property name="text"> - <string>32 GB</string> - </property> - </item> - <item> - <property name="text"> - <string>64 GB</string> - </property> - </item> - <item> - <property name="text"> - <string>128 GB</string> - </property> - </item> - <item> - <property name="text"> - <string>256 GB</string> - </property> - </item> - <item> - <property name="text"> - <string>1 TB</string> - </property> - </item> - </widget> - </item> - <item row="2" column="1"> - <widget class="QComboBox" name="usrnand_size"> - <item> - <property name="text"> - <string>26 GB</string> - </property> - </item> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_6"> - <property name="text"> - <string>User NAND</string> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="label_7"> - <property name="text"> - <string>NAND</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QComboBox" name="nand_size"> - <item> - <property name="text"> - <string>29.1 GB</string> - </property> - </item> - </widget> - </item> - </layout> - </widget> - </item> - <item> <widget class="QGroupBox" name="groupBox_4"> <property name="title"> <string>Patch Manager</string> diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 1fb62d1cf..20316c9cc 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -65,6 +65,8 @@ void ConfigureGeneral::ApplyConfiguration() { Settings::values.use_frame_limit.SetValue(ui->toggle_frame_limit->checkState() == Qt::Checked); Settings::values.frame_limit.SetValue(ui->frame_limit->value()); + } + if (Settings::values.use_multi_core.UsingGlobal()) { Settings::values.use_multi_core.SetValue(ui->use_multi_core->isChecked()); } } else { diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index bfb600df0..ab7fc7a24 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -531,8 +531,8 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) { UISettings::GameDir& game_dir = *selected.data(GameListDir::GameDirRole).value<UISettings::GameDir*>(); - QAction* move_up = context_menu.addAction(tr(u8"\U000025b2 Move Up")); - QAction* move_down = context_menu.addAction(tr(u8"\U000025bc Move Down ")); + QAction* move_up = context_menu.addAction(tr("\u25B2 Move Up")); + QAction* move_down = context_menu.addAction(tr("\u25bc Move Down")); QAction* open_directory_location = context_menu.addAction(tr("Open Directory Location")); const int row = selected.row(); diff --git a/src/yuzu/install_dialog.cpp b/src/yuzu/install_dialog.cpp new file mode 100644 index 000000000..06b0b1874 --- /dev/null +++ b/src/yuzu/install_dialog.cpp @@ -0,0 +1,72 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <QCheckBox> +#include <QDialogButtonBox> +#include <QFileInfo> +#include <QHBoxLayout> +#include <QLabel> +#include <QListWidget> +#include <QVBoxLayout> +#include "yuzu/install_dialog.h" +#include "yuzu/uisettings.h" + +InstallDialog::InstallDialog(QWidget* parent, const QStringList& files) : QDialog(parent) { + file_list = new QListWidget(this); + + for (const QString& file : files) { + QListWidgetItem* item = new QListWidgetItem(QFileInfo(file).fileName(), file_list); + item->setData(Qt::UserRole, file); + item->setFlags(item->flags() | Qt::ItemIsUserCheckable); + item->setCheckState(Qt::Checked); + } + + file_list->setMinimumWidth((file_list->sizeHintForColumn(0) * 11) / 10); + + vbox_layout = new QVBoxLayout; + + hbox_layout = new QHBoxLayout; + + description = new QLabel(tr("Please confirm these are the files you wish to install.")); + + update_description = + new QLabel(tr("Installing an Update or DLC will overwrite the previously installed one.")); + + buttons = new QDialogButtonBox; + buttons->addButton(QDialogButtonBox::Cancel); + buttons->addButton(tr("Install"), QDialogButtonBox::AcceptRole); + + connect(buttons, &QDialogButtonBox::accepted, this, &InstallDialog::accept); + connect(buttons, &QDialogButtonBox::rejected, this, &InstallDialog::reject); + + hbox_layout->addWidget(buttons); + + vbox_layout->addWidget(description); + vbox_layout->addWidget(update_description); + vbox_layout->addWidget(file_list); + vbox_layout->addLayout(hbox_layout); + + setLayout(vbox_layout); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setWindowTitle(tr("Install Files to NAND")); +} + +InstallDialog::~InstallDialog() = default; + +QStringList InstallDialog::GetFiles() const { + QStringList files; + + for (int i = 0; i < file_list->count(); ++i) { + const QListWidgetItem* item = file_list->item(i); + if (item->checkState() == Qt::Checked) { + files.append(item->data(Qt::UserRole).toString()); + } + } + + return files; +} + +int InstallDialog::GetMinimumWidth() const { + return file_list->width(); +} diff --git a/src/yuzu/install_dialog.h b/src/yuzu/install_dialog.h new file mode 100644 index 000000000..e4aba1b06 --- /dev/null +++ b/src/yuzu/install_dialog.h @@ -0,0 +1,36 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <QDialog> + +class QCheckBox; +class QDialogButtonBox; +class QHBoxLayout; +class QLabel; +class QListWidget; +class QVBoxLayout; + +class InstallDialog : public QDialog { + Q_OBJECT + +public: + explicit InstallDialog(QWidget* parent, const QStringList& files); + ~InstallDialog() override; + + QStringList GetFiles() const; + bool ShouldOverwriteFiles() const; + int GetMinimumWidth() const; + +private: + QListWidget* file_list; + + QVBoxLayout* vbox_layout; + QHBoxLayout* hbox_layout; + + QLabel* description; + QLabel* update_description; + QDialogButtonBox* buttons; +}; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 4d501a8f9..9f758605a 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -107,6 +107,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/game_list.h" #include "yuzu/game_list_p.h" #include "yuzu/hotkeys.h" +#include "yuzu/install_dialog.h" #include "yuzu/loading_screen.h" #include "yuzu/main.h" #include "yuzu/uisettings.h" @@ -278,17 +279,21 @@ GMainWindow::~GMainWindow() { } void GMainWindow::ProfileSelectorSelectProfile() { - QtProfileSelectionDialog dialog(this); - dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | - Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); - dialog.setWindowModality(Qt::WindowModal); - if (dialog.exec() == QDialog::Rejected) { - emit ProfileSelectorFinishedSelection(std::nullopt); - return; + const Service::Account::ProfileManager manager; + int index = 0; + if (manager.GetUserCount() != 1) { + QtProfileSelectionDialog dialog(this); + dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | + Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); + dialog.setWindowModality(Qt::WindowModal); + if (dialog.exec() == QDialog::Rejected) { + emit ProfileSelectorFinishedSelection(std::nullopt); + return; + } + index = dialog.GetIndex(); } - Service::Account::ProfileManager manager; - const auto uuid = manager.GetUser(static_cast<std::size_t>(dialog.GetIndex())); + const auto uuid = manager.GetUser(static_cast<std::size_t>(index)); if (!uuid.has_value()) { emit ProfileSelectorFinishedSelection(std::nullopt); return; @@ -847,6 +852,9 @@ void GMainWindow::ConnectWidgetEvents() { connect(game_list, &GameList::OpenPerGameGeneralRequested, this, &GMainWindow::OnGameListOpenPerGameProperties); + connect(this, &GMainWindow::UpdateInstallProgress, this, + &GMainWindow::IncrementInstallProgress); + connect(this, &GMainWindow::EmulationStarting, render_window, &GRenderWindow::OnEmulationStarting); connect(this, &GMainWindow::EmulationStopping, render_window, @@ -1593,187 +1601,255 @@ void GMainWindow::OnMenuLoadFolder() { } } +void GMainWindow::IncrementInstallProgress() { + install_progress->setValue(install_progress->value() + 1); +} + void GMainWindow::OnMenuInstallToNAND() { const QString file_filter = tr("Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive " - "(*.nca);;Nintendo Submissions Package (*.nsp);;NX Cartridge " + "(*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge " "Image (*.xci)"); - QString filename = QFileDialog::getOpenFileName(this, tr("Install File"), - UISettings::values.roms_path, file_filter); - if (filename.isEmpty()) { + QStringList filenames = QFileDialog::getOpenFileNames( + this, tr("Install Files"), UISettings::values.roms_path, file_filter); + + if (filenames.isEmpty()) { return; } + InstallDialog installDialog(this, filenames); + if (installDialog.exec() == QDialog::Rejected) { + return; + } + + const QStringList files = installDialog.GetFiles(); + + if (files.isEmpty()) { + return; + } + + int remaining = filenames.size(); + + // This would only overflow above 2^43 bytes (8.796 TB) + int total_size = 0; + for (const QString& file : files) { + total_size += static_cast<int>(QFile(file).size() / 0x1000); + } + if (total_size < 0) { + LOG_CRITICAL(Frontend, "Attempting to install too many files, aborting."); + return; + } + + QStringList new_files{}; // Newly installed files that do not yet exist in the NAND + QStringList overwritten_files{}; // Files that overwrote those existing in the NAND + QStringList failed_files{}; // Files that failed to install due to errors + + ui.action_Install_File_NAND->setEnabled(false); + + install_progress = new QProgressDialog(QStringLiteral(""), tr("Cancel"), 0, total_size, this); + install_progress->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint & + ~Qt::WindowMaximizeButtonHint); + install_progress->setAttribute(Qt::WA_DeleteOnClose, true); + install_progress->setFixedWidth(installDialog.GetMinimumWidth() + 40); + install_progress->show(); + + for (const QString& file : files) { + install_progress->setWindowTitle(tr("%n file(s) remaining", "", remaining)); + install_progress->setLabelText( + tr("Installing file \"%1\"...").arg(QFileInfo(file).fileName())); + + QFuture<InstallResult> future; + InstallResult result; + + if (file.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) || + file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { + + future = QtConcurrent::run([this, &file] { return InstallNSPXCI(file); }); + + while (!future.isFinished()) { + QCoreApplication::processEvents(); + } + + result = future.result(); + + } else { + result = InstallNCA(file); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + + switch (result) { + case InstallResult::Success: + new_files.append(QFileInfo(file).fileName()); + break; + case InstallResult::Overwrite: + overwritten_files.append(QFileInfo(file).fileName()); + break; + case InstallResult::Failure: + failed_files.append(QFileInfo(file).fileName()); + break; + } + + --remaining; + } + + install_progress->close(); + + const QString install_results = + (new_files.isEmpty() ? QStringLiteral("") + : tr("%n file(s) were newly installed\n", "", new_files.size())) + + (overwritten_files.isEmpty() + ? QStringLiteral("") + : tr("%n file(s) were overwritten\n", "", overwritten_files.size())) + + (failed_files.isEmpty() ? QStringLiteral("") + : tr("%n file(s) failed to install\n", "", failed_files.size())); + + QMessageBox::information(this, tr("Install Results"), install_results); + game_list->PopulateAsync(UISettings::values.game_dirs); + FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP + + "game_list"); + ui.action_Install_File_NAND->setEnabled(true); +} + +InstallResult GMainWindow::InstallNSPXCI(const QString& filename) { const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, std::size_t block_size) { - if (src == nullptr || dest == nullptr) + if (src == nullptr || dest == nullptr) { return false; - if (!dest->Resize(src->GetSize())) + } + if (!dest->Resize(src->GetSize())) { return false; + } std::array<u8, 0x1000> buffer{}; - const int progress_maximum = static_cast<int>(src->GetSize() / buffer.size()); - - QProgressDialog progress( - tr("Installing file \"%1\"...").arg(QString::fromStdString(src->GetName())), - tr("Cancel"), 0, progress_maximum, this); - progress.setWindowModality(Qt::WindowModal); for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { - if (progress.wasCanceled()) { + if (install_progress->wasCanceled()) { dest->Resize(0); return false; } - const int progress_value = static_cast<int>(i / buffer.size()); - progress.setValue(progress_value); + emit UpdateInstallProgress(); const auto read = src->Read(buffer.data(), buffer.size(), i); dest->Write(buffer.data(), read, i); } - return true; }; - const auto success = [this]() { - QMessageBox::information(this, tr("Successfully Installed"), - tr("The file was successfully installed.")); - game_list->PopulateAsync(UISettings::values.game_dirs); - FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + - DIR_SEP + "game_list"); - }; - - const auto failed = [this]() { - QMessageBox::warning( - this, tr("Failed to Install"), - tr("There was an error while attempting to install the provided file. It " - "could have an incorrect format or be missing metadata. Please " - "double-check your file and try again.")); - }; - - const auto overwrite = [this]() { - return QMessageBox::question(this, tr("Failed to Install"), - tr("The file you are attempting to install already exists " - "in the cache. Would you like to overwrite it?")) == - QMessageBox::Yes; - }; - - if (filename.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) || - filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { - std::shared_ptr<FileSys::NSP> nsp; - if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { - nsp = std::make_shared<FileSys::NSP>( - vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); - if (nsp->IsExtractedType()) - failed(); - } else { - const auto xci = std::make_shared<FileSys::XCI>( - vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); - nsp = xci->GetSecurePartitionNSP(); - } - - if (nsp->GetStatus() != Loader::ResultStatus::Success) { - failed(); - return; - } - const auto res = Core::System::GetInstance() - .GetFileSystemController() - .GetUserNANDContents() - ->InstallEntry(*nsp, false, qt_raw_copy); - if (res == FileSys::InstallResult::Success) { - success(); - } else { - if (res == FileSys::InstallResult::ErrorAlreadyExists) { - if (overwrite()) { - const auto res2 = Core::System::GetInstance() - .GetFileSystemController() - .GetUserNANDContents() - ->InstallEntry(*nsp, true, qt_raw_copy); - if (res2 == FileSys::InstallResult::Success) { - success(); - } else { - failed(); - } - } - } else { - failed(); - } + std::shared_ptr<FileSys::NSP> nsp; + if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { + nsp = std::make_shared<FileSys::NSP>( + vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); + if (nsp->IsExtractedType()) { + return InstallResult::Failure; } } else { - const auto nca = std::make_shared<FileSys::NCA>( + const auto xci = std::make_shared<FileSys::XCI>( vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); - const auto id = nca->GetStatus(); + nsp = xci->GetSecurePartitionNSP(); + } - // Game updates necessary are missing base RomFS - if (id != Loader::ResultStatus::Success && - id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { - failed(); - return; - } + if (nsp->GetStatus() != Loader::ResultStatus::Success) { + return InstallResult::Failure; + } + const auto res = + Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->InstallEntry( + *nsp, true, qt_raw_copy); + if (res == FileSys::InstallResult::Success) { + return InstallResult::Success; + } else if (res == FileSys::InstallResult::OverwriteExisting) { + return InstallResult::Overwrite; + } else { + return InstallResult::Failure; + } +} - const QStringList tt_options{tr("System Application"), - tr("System Archive"), - tr("System Application Update"), - tr("Firmware Package (Type A)"), - tr("Firmware Package (Type B)"), - tr("Game"), - tr("Game Update"), - tr("Game DLC"), - tr("Delta Title")}; - bool ok; - const auto item = QInputDialog::getItem( - this, tr("Select NCA Install Type..."), - tr("Please select the type of title you would like to install this NCA as:\n(In " - "most instances, the default 'Game' is fine.)"), - tt_options, 5, false, &ok); - - auto index = tt_options.indexOf(item); - if (!ok || index == -1) { - QMessageBox::warning(this, tr("Failed to Install"), - tr("The title type you selected for the NCA is invalid.")); - return; +InstallResult GMainWindow::InstallNCA(const QString& filename) { + const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, + const FileSys::VirtualFile& dest, std::size_t block_size) { + if (src == nullptr || dest == nullptr) { + return false; } - - // If index is equal to or past Game, add the jump in TitleType. - if (index >= 5) { - index += static_cast<size_t>(FileSys::TitleType::Application) - - static_cast<size_t>(FileSys::TitleType::FirmwarePackageB); + if (!dest->Resize(src->GetSize())) { + return false; } - FileSys::InstallResult res; - if (index >= static_cast<s32>(FileSys::TitleType::Application)) { - res = Core::System::GetInstance() - .GetFileSystemController() - .GetUserNANDContents() - ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false, - qt_raw_copy); - } else { - res = Core::System::GetInstance() - .GetFileSystemController() - .GetSystemNANDContents() - ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false, - qt_raw_copy); - } + std::array<u8, 0x1000> buffer{}; - if (res == FileSys::InstallResult::Success) { - success(); - } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { - if (overwrite()) { - const auto res2 = Core::System::GetInstance() - .GetFileSystemController() - .GetUserNANDContents() - ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), - true, qt_raw_copy); - if (res2 == FileSys::InstallResult::Success) { - success(); - } else { - failed(); - } + for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { + if (install_progress->wasCanceled()) { + dest->Resize(0); + return false; } - } else { - failed(); + + emit UpdateInstallProgress(); + + const auto read = src->Read(buffer.data(), buffer.size(), i); + dest->Write(buffer.data(), read, i); } + return true; + }; + + const auto nca = + std::make_shared<FileSys::NCA>(vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); + const auto id = nca->GetStatus(); + + // Game updates necessary are missing base RomFS + if (id != Loader::ResultStatus::Success && + id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { + return InstallResult::Failure; + } + + const QStringList tt_options{tr("System Application"), + tr("System Archive"), + tr("System Application Update"), + tr("Firmware Package (Type A)"), + tr("Firmware Package (Type B)"), + tr("Game"), + tr("Game Update"), + tr("Game DLC"), + tr("Delta Title")}; + bool ok; + const auto item = QInputDialog::getItem( + this, tr("Select NCA Install Type..."), + tr("Please select the type of title you would like to install this NCA as:\n(In " + "most instances, the default 'Game' is fine.)"), + tt_options, 5, false, &ok); + + auto index = tt_options.indexOf(item); + if (!ok || index == -1) { + QMessageBox::warning(this, tr("Failed to Install"), + tr("The title type you selected for the NCA is invalid.")); + return InstallResult::Failure; + } + + // If index is equal to or past Game, add the jump in TitleType. + if (index >= 5) { + index += static_cast<size_t>(FileSys::TitleType::Application) - + static_cast<size_t>(FileSys::TitleType::FirmwarePackageB); + } + + FileSys::InstallResult res; + if (index >= static_cast<s32>(FileSys::TitleType::Application)) { + res = Core::System::GetInstance() + .GetFileSystemController() + .GetUserNANDContents() + ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy); + } else { + res = Core::System::GetInstance() + .GetFileSystemController() + .GetSystemNANDContents() + ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy); + } + + if (res == FileSys::InstallResult::Success) { + return InstallResult::Success; + } else if (res == FileSys::InstallResult::OverwriteExisting) { + return InstallResult::Overwrite; + } else { + return InstallResult::Failure; } } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 8e3d39c38..adff65fb5 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -28,6 +28,7 @@ class MicroProfileDialog; class ProfilerWidget; class QLabel; class QPushButton; +class QProgressDialog; class WaitTreeWidget; enum class GameListOpenTarget; class GameListPlaceholder; @@ -47,6 +48,12 @@ enum class EmulatedDirectoryTarget { SDMC, }; +enum class InstallResult { + Success, + Overwrite, + Failure, +}; + enum class ReinitializeKeyBehavior { NoWarning, Warning, @@ -102,6 +109,8 @@ signals: // Signal that tells widgets to update icons to use the current theme void UpdateThemedIcons(); + void UpdateInstallProgress(); + void ErrorDisplayFinished(); void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid); @@ -198,6 +207,7 @@ private slots: void OnGameListOpenPerGameProperties(const std::string& file); void OnMenuLoadFile(); void OnMenuLoadFolder(); + void IncrementInstallProgress(); void OnMenuInstallToNAND(); void OnMenuRecentFile(); void OnConfigure(); @@ -218,6 +228,8 @@ private slots: private: std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id); + InstallResult InstallNSPXCI(const QString& filename); + InstallResult InstallNCA(const QString& filename); void UpdateWindowTitle(const std::string& title_name = {}, const std::string& title_version = {}); void UpdateStatusBar(); @@ -272,6 +284,9 @@ private: HotkeyRegistry hotkey_registry; + // Install progress dialog + QProgressDialog* install_progress; + protected: void dropEvent(QDropEvent* event) override; void dragEnterEvent(QDragEnterEvent* event) override; diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index bee6e107e..c3a1d715e 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui @@ -130,7 +130,7 @@ <bool>true</bool> </property> <property name="text"> - <string>Install File to NAND...</string> + <string>Install Files to NAND...</string> </property> </action> <action name="action_Load_File"> diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index 23763144f..7773228c8 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -335,15 +335,6 @@ void Config::ReadValues() { Settings::values.gamecard_current_game = sdl2_config->GetBoolean("Data Storage", "gamecard_current_game", false); Settings::values.gamecard_path = sdl2_config->Get("Data Storage", "gamecard_path", ""); - Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(sdl2_config->GetInteger( - "Data Storage", "nand_total_size", static_cast<long>(Settings::NANDTotalSize::S29_1GB))); - Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(sdl2_config->GetInteger( - "Data Storage", "nand_user_size", static_cast<long>(Settings::NANDUserSize::S26GB))); - Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>( - sdl2_config->GetInteger("Data Storage", "nand_system_size", - static_cast<long>(Settings::NANDSystemSize::S2_5GB))); - Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(sdl2_config->GetInteger( - "Data Storage", "sdmc_size", static_cast<long>(Settings::SDMCSize::S16GB))); // System Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false); @@ -437,8 +428,6 @@ void Config::ReadValues() { Settings::values.reporting_services = sdl2_config->GetBoolean("Debugging", "reporting_services", false); Settings::values.quest_flag = sdl2_config->GetBoolean("Debugging", "quest_flag", false); - Settings::values.disable_cpu_opt = - sdl2_config->GetBoolean("Debugging", "disable_cpu_opt", false); Settings::values.disable_macro_jit = sdl2_config->GetBoolean("Debugging", "disable_macro_jit", false); diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index 45c07ed5d..5bed47fd7 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h @@ -97,6 +97,39 @@ udp_pad_index= # 0 (default): Disabled, 1: Enabled use_multi_core= +[Cpu] +# Enable inline page tables optimization (faster guest memory access) +# 0: Disabled, 1 (default): Enabled +cpuopt_page_tables = + +# Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps) +# 0: Disabled, 1 (default): Enabled +cpuopt_block_linking = + +# Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns) +# 0: Disabled, 1 (default): Enabled +cpuopt_return_stack_buffer = + +# Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture) +# 0: Disabled, 1 (default): Enabled +cpuopt_fast_dispatcher = + +# Enable context elimination CPU Optimization (reduce host memory use for guest context) +# 0: Disabled, 1 (default): Enabled +cpuopt_context_elimination = + +# Enable constant propagation CPU optimization (basic IR optimization) +# 0: Disabled, 1 (default): Enabled +cpuopt_const_prop = + +# Enable miscellaneous CPU optimizations (basic IR optimization) +# 0: Disabled, 1 (default): Enabled +cpuopt_misc_ir = + +# Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access) +# 0: Disabled, 1 (default): Enabled +cpuopt_reduce_misalign_checks = + [Renderer] # Which backend API to use. # 0 (default): OpenGL, 1: Vulkan @@ -283,9 +316,6 @@ dump_nso=false # 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 = -# Determines whether or not JIT CPU optimizations are enabled -# false: Optimizations Enabled, true: Optimizations Disabled -disable_cpu_opt = # Enables/Disables the macro JIT compiler disable_macro_jit=false diff --git a/src/yuzu_tester/default_ini.h b/src/yuzu_tester/default_ini.h index 41bbbbf60..3eb64e9d7 100644 --- a/src/yuzu_tester/default_ini.h +++ b/src/yuzu_tester/default_ini.h @@ -12,6 +12,39 @@ const char* sdl2_config_file = R"( # 0 (default): Disabled, 1: Enabled use_multi_core= +[Cpu] +# Enable inline page tables optimization (faster guest memory access) +# 0: Disabled, 1 (default): Enabled +cpuopt_page_tables = + +# Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps) +# 0: Disabled, 1 (default): Enabled +cpuopt_block_linking = + +# Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns) +# 0: Disabled, 1 (default): Enabled +cpuopt_return_stack_buffer = + +# Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture) +# 0: Disabled, 1 (default): Enabled +cpuopt_fast_dispatcher = + +# Enable context elimination CPU Optimization (reduce host memory use for guest context) +# 0: Disabled, 1 (default): Enabled +cpuopt_context_elimination = + +# Enable constant propagation CPU optimization (basic IR optimization) +# 0: Disabled, 1 (default): Enabled +cpuopt_const_prop = + +# Enable miscellaneous CPU optimizations (basic IR optimization) +# 0: Disabled, 1 (default): Enabled +cpuopt_misc_ir = + +# Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access) +# 0: Disabled, 1 (default): Enabled +cpuopt_reduce_misalign_checks = + [Renderer] # Whether to use software or hardware rendering. # 0: Software, 1 (default): Hardware |