diff options
Diffstat (limited to 'src')
55 files changed, 1981 insertions, 1244 deletions
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 @@ | |||
| 17 | 17 | ||
| 18 | #pragma once | 18 | #pragma once |
| 19 | 19 | ||
| 20 | #include <type_traits> | ||
| 21 | |||
| 22 | #if defined(_MSC_VER) | 20 | #if defined(_MSC_VER) |
| 23 | #include <cstdlib> | 21 | #include <cstdlib> |
| 24 | #endif | 22 | #endif |
| 23 | #include <bit> | ||
| 25 | #include <cstring> | 24 | #include <cstring> |
| 25 | #include <type_traits> | ||
| 26 | #include "common/common_types.h" | 26 | #include "common/common_types.h" |
| 27 | 27 | ||
| 28 | // GCC | ||
| 29 | #ifdef __GNUC__ | ||
| 30 | |||
| 31 | #if __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) && !defined(COMMON_LITTLE_ENDIAN) | ||
| 32 | #define COMMON_LITTLE_ENDIAN 1 | ||
| 33 | #elif __BYTE_ORDER__ && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) && !defined(COMMON_BIG_ENDIAN) | ||
| 34 | #define COMMON_BIG_ENDIAN 1 | ||
| 35 | #endif | ||
| 36 | |||
| 37 | // LLVM/clang | ||
| 38 | #elif defined(__clang__) | ||
| 39 | |||
| 40 | #if __LITTLE_ENDIAN__ && !defined(COMMON_LITTLE_ENDIAN) | ||
| 41 | #define COMMON_LITTLE_ENDIAN 1 | ||
| 42 | #elif __BIG_ENDIAN__ && !defined(COMMON_BIG_ENDIAN) | ||
| 43 | #define COMMON_BIG_ENDIAN 1 | ||
| 44 | #endif | ||
| 45 | |||
| 46 | // MSVC | ||
| 47 | #elif defined(_MSC_VER) && !defined(COMMON_BIG_ENDIAN) && !defined(COMMON_LITTLE_ENDIAN) | ||
| 48 | |||
| 49 | #define COMMON_LITTLE_ENDIAN 1 | ||
| 50 | #endif | ||
| 51 | |||
| 52 | // Worst case, default to little endian. | ||
| 53 | #if !COMMON_BIG_ENDIAN && !COMMON_LITTLE_ENDIAN | ||
| 54 | #define COMMON_LITTLE_ENDIAN 1 | ||
| 55 | #endif | ||
| 56 | |||
| 57 | namespace Common { | 28 | namespace Common { |
| 58 | 29 | ||
| 59 | #ifdef _MSC_VER | 30 | #ifdef _MSC_VER |
| @@ -675,17 +646,8 @@ struct AddEndian<T, SwapTag> { | |||
| 675 | }; | 646 | }; |
| 676 | 647 | ||
| 677 | // Alias LETag/BETag as KeepTag/SwapTag depending on the system | 648 | // Alias LETag/BETag as KeepTag/SwapTag depending on the system |
| 678 | #if COMMON_LITTLE_ENDIAN | 649 | using LETag = std::conditional_t<std::endian::native == std::endian::little, KeepTag, SwapTag>; |
| 679 | 650 | using BETag = std::conditional_t<std::endian::native == std::endian::big, KeepTag, SwapTag>; | |
| 680 | using LETag = KeepTag; | ||
| 681 | using BETag = SwapTag; | ||
| 682 | |||
| 683 | #else | ||
| 684 | |||
| 685 | using BETag = KeepTag; | ||
| 686 | using LETag = SwapTag; | ||
| 687 | |||
| 688 | #endif | ||
| 689 | 651 | ||
| 690 | // Aliases for LE types | 652 | // Aliases for LE types |
| 691 | using u16_le = AddEndian<u16, LETag>::type; | 653 | 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& | |||
| 142 | // Timing | 142 | // Timing |
| 143 | config.wall_clock_cntpct = uses_wall_clock; | 143 | config.wall_clock_cntpct = uses_wall_clock; |
| 144 | 144 | ||
| 145 | // Optimizations | 145 | // Safe optimizations |
| 146 | if (Settings::values.disable_cpu_opt) { | 146 | if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) { |
| 147 | config.enable_optimizations = false; | 147 | if (!Settings::values.cpuopt_page_tables) { |
| 148 | config.enable_fast_dispatch = false; | 148 | config.page_table = nullptr; |
| 149 | } | ||
| 150 | if (!Settings::values.cpuopt_block_linking) { | ||
| 151 | config.optimizations &= ~Dynarmic::OptimizationFlag::BlockLinking; | ||
| 152 | } | ||
| 153 | if (!Settings::values.cpuopt_return_stack_buffer) { | ||
| 154 | config.optimizations &= ~Dynarmic::OptimizationFlag::ReturnStackBuffer; | ||
| 155 | } | ||
| 156 | if (!Settings::values.cpuopt_fast_dispatcher) { | ||
| 157 | config.optimizations &= ~Dynarmic::OptimizationFlag::FastDispatch; | ||
| 158 | } | ||
| 159 | if (!Settings::values.cpuopt_context_elimination) { | ||
| 160 | config.optimizations &= ~Dynarmic::OptimizationFlag::GetSetElimination; | ||
| 161 | } | ||
| 162 | if (!Settings::values.cpuopt_const_prop) { | ||
| 163 | config.optimizations &= ~Dynarmic::OptimizationFlag::ConstProp; | ||
| 164 | } | ||
| 165 | if (!Settings::values.cpuopt_misc_ir) { | ||
| 166 | config.optimizations &= ~Dynarmic::OptimizationFlag::MiscIROpt; | ||
| 167 | } | ||
| 168 | if (!Settings::values.cpuopt_reduce_misalign_checks) { | ||
| 169 | config.only_detect_misalignment_via_page_table_on_page_boundary = false; | ||
| 170 | } | ||
| 149 | } | 171 | } |
| 150 | 172 | ||
| 151 | return std::make_unique<Dynarmic::A32::Jit>(config); | 173 | 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& | |||
| 191 | // Unpredictable instructions | 191 | // Unpredictable instructions |
| 192 | config.define_unpredictable_behaviour = true; | 192 | config.define_unpredictable_behaviour = true; |
| 193 | 193 | ||
| 194 | // Optimizations | ||
| 195 | if (Settings::values.disable_cpu_opt) { | ||
| 196 | config.enable_optimizations = false; | ||
| 197 | config.enable_fast_dispatch = false; | ||
| 198 | } | ||
| 199 | |||
| 200 | // Timing | 194 | // Timing |
| 201 | config.wall_clock_cntpct = uses_wall_clock; | 195 | config.wall_clock_cntpct = uses_wall_clock; |
| 202 | 196 | ||
| 197 | // Safe optimizations | ||
| 198 | if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) { | ||
| 199 | if (!Settings::values.cpuopt_page_tables) { | ||
| 200 | config.page_table = nullptr; | ||
| 201 | } | ||
| 202 | if (!Settings::values.cpuopt_block_linking) { | ||
| 203 | config.optimizations &= ~Dynarmic::OptimizationFlag::BlockLinking; | ||
| 204 | } | ||
| 205 | if (!Settings::values.cpuopt_return_stack_buffer) { | ||
| 206 | config.optimizations &= ~Dynarmic::OptimizationFlag::ReturnStackBuffer; | ||
| 207 | } | ||
| 208 | if (!Settings::values.cpuopt_fast_dispatcher) { | ||
| 209 | config.optimizations &= ~Dynarmic::OptimizationFlag::FastDispatch; | ||
| 210 | } | ||
| 211 | if (!Settings::values.cpuopt_context_elimination) { | ||
| 212 | config.optimizations &= ~Dynarmic::OptimizationFlag::GetSetElimination; | ||
| 213 | } | ||
| 214 | if (!Settings::values.cpuopt_const_prop) { | ||
| 215 | config.optimizations &= ~Dynarmic::OptimizationFlag::ConstProp; | ||
| 216 | } | ||
| 217 | if (!Settings::values.cpuopt_misc_ir) { | ||
| 218 | config.optimizations &= ~Dynarmic::OptimizationFlag::MiscIROpt; | ||
| 219 | } | ||
| 220 | if (!Settings::values.cpuopt_reduce_misalign_checks) { | ||
| 221 | config.only_detect_misalignment_via_page_table_on_page_boundary = false; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 203 | return std::make_shared<Dynarmic::A64::Jit>(config); | 225 | return std::make_shared<Dynarmic::A64::Jit>(config); |
| 204 | } | 226 | } |
| 205 | 227 | ||
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 @@ | |||
| 9 | #include <functional> | 9 | #include <functional> |
| 10 | #include <memory> | 10 | #include <memory> |
| 11 | #include <thread> | 11 | #include <thread> |
| 12 | |||
| 13 | #include "common/fiber.h" | ||
| 14 | #include "common/thread.h" | ||
| 12 | #include "core/hardware_properties.h" | 15 | #include "core/hardware_properties.h" |
| 13 | 16 | ||
| 14 | namespace Common { | 17 | namespace Common { |
| @@ -46,9 +49,9 @@ public: | |||
| 46 | 49 | ||
| 47 | void Pause(bool paused); | 50 | void Pause(bool paused); |
| 48 | 51 | ||
| 49 | std::function<void(void*)> GetGuestThreadStartFunc(); | 52 | static std::function<void(void*)> GetGuestThreadStartFunc(); |
| 50 | std::function<void(void*)> GetIdleThreadStartFunc(); | 53 | static std::function<void(void*)> GetIdleThreadStartFunc(); |
| 51 | std::function<void(void*)> GetSuspendThreadStartFunc(); | 54 | static std::function<void(void*)> GetSuspendThreadStartFunc(); |
| 52 | void* GetStartFuncParamater(); | 55 | void* GetStartFuncParamater(); |
| 53 | 56 | ||
| 54 | void PreemptSingleCore(bool from_running_enviroment = true); | 57 | void PreemptSingleCore(bool from_running_enviroment = true); |
| @@ -97,7 +100,6 @@ private: | |||
| 97 | bool is_async_gpu{}; | 100 | bool is_async_gpu{}; |
| 98 | bool is_multicore{}; | 101 | bool is_multicore{}; |
| 99 | std::atomic<std::size_t> current_core{}; | 102 | std::atomic<std::size_t> current_core{}; |
| 100 | std::size_t preemption_count{}; | ||
| 101 | std::size_t idle_count{}; | 103 | std::size_t idle_count{}; |
| 102 | static constexpr std::size_t max_cycle_runs = 5; | 104 | static constexpr std::size_t max_cycle_runs = 5; |
| 103 | 105 | ||
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 @@ | |||
| 12 | 12 | ||
| 13 | namespace FileSys { | 13 | namespace FileSys { |
| 14 | 14 | ||
| 15 | constexpr u64 NAND_USER_SIZE = 0x680000000; // 26624 MiB | ||
| 16 | constexpr u64 NAND_SYSTEM_SIZE = 0xA0000000; // 2560 MiB | ||
| 17 | constexpr u64 NAND_TOTAL_SIZE = 0x747C00000; // 29820 MiB | ||
| 18 | |||
| 15 | BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir dump_root_) | 19 | BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir dump_root_) |
| 16 | : nand_root(std::move(nand_root_)), load_root(std::move(load_root_)), | 20 | : nand_root(std::move(nand_root_)), load_root(std::move(load_root_)), |
| 17 | dump_root(std::move(dump_root_)), | 21 | dump_root(std::move(dump_root_)), |
| @@ -110,30 +114,29 @@ VirtualDir BISFactory::GetImageDirectory() const { | |||
| 110 | 114 | ||
| 111 | u64 BISFactory::GetSystemNANDFreeSpace() const { | 115 | u64 BISFactory::GetSystemNANDFreeSpace() const { |
| 112 | const auto sys_dir = GetOrCreateDirectoryRelative(nand_root, "/system"); | 116 | const auto sys_dir = GetOrCreateDirectoryRelative(nand_root, "/system"); |
| 113 | if (sys_dir == nullptr) | 117 | if (sys_dir == nullptr) { |
| 114 | return 0; | 118 | return GetSystemNANDTotalSpace(); |
| 119 | } | ||
| 115 | 120 | ||
| 116 | return GetSystemNANDTotalSpace() - sys_dir->GetSize(); | 121 | return GetSystemNANDTotalSpace() - sys_dir->GetSize(); |
| 117 | } | 122 | } |
| 118 | 123 | ||
| 119 | u64 BISFactory::GetSystemNANDTotalSpace() const { | 124 | u64 BISFactory::GetSystemNANDTotalSpace() const { |
| 120 | return static_cast<u64>(Settings::values.nand_system_size); | 125 | return NAND_SYSTEM_SIZE; |
| 121 | } | 126 | } |
| 122 | 127 | ||
| 123 | u64 BISFactory::GetUserNANDFreeSpace() const { | 128 | u64 BISFactory::GetUserNANDFreeSpace() const { |
| 124 | const auto usr_dir = GetOrCreateDirectoryRelative(nand_root, "/user"); | 129 | // For some reason games such as BioShock 1 checks whether this is exactly 0x680000000 bytes. |
| 125 | if (usr_dir == nullptr) | 130 | // Set the free space to be 1 MiB less than the total as a workaround to this issue. |
| 126 | return 0; | 131 | return GetUserNANDTotalSpace() - 0x100000; |
| 127 | |||
| 128 | return GetUserNANDTotalSpace() - usr_dir->GetSize(); | ||
| 129 | } | 132 | } |
| 130 | 133 | ||
| 131 | u64 BISFactory::GetUserNANDTotalSpace() const { | 134 | u64 BISFactory::GetUserNANDTotalSpace() const { |
| 132 | return static_cast<u64>(Settings::values.nand_user_size); | 135 | return NAND_USER_SIZE; |
| 133 | } | 136 | } |
| 134 | 137 | ||
| 135 | u64 BISFactory::GetFullNANDTotalSpace() const { | 138 | u64 BISFactory::GetFullNANDTotalSpace() const { |
| 136 | return static_cast<u64>(Settings::values.nand_total_size); | 139 | return NAND_TOTAL_SIZE; |
| 137 | } | 140 | } |
| 138 | 141 | ||
| 139 | VirtualDir BISFactory::GetBCATDirectory(u64 title_id) const { | 142 | 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 | |||
| 547 | return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy); | 547 | return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy); |
| 548 | } | 548 | } |
| 549 | 549 | ||
| 550 | bool RegisteredCache::RemoveExistingEntry(u64 title_id) { | ||
| 551 | const auto delete_nca = [this](const NcaID& id) { | ||
| 552 | const auto path = GetRelativePathFromNcaID(id, false, true, false); | ||
| 553 | |||
| 554 | if (dir->GetFileRelative(path) == nullptr) { | ||
| 555 | return false; | ||
| 556 | } | ||
| 557 | |||
| 558 | Core::Crypto::SHA256Hash hash{}; | ||
| 559 | mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0); | ||
| 560 | const auto dirname = fmt::format("000000{:02X}", hash[0]); | ||
| 561 | |||
| 562 | const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname); | ||
| 563 | |||
| 564 | const auto res = dir2->DeleteFile(fmt::format("{}.nca", Common::HexToString(id, false))); | ||
| 565 | |||
| 566 | return res; | ||
| 567 | }; | ||
| 568 | |||
| 569 | // If an entry exists in the registered cache, remove it | ||
| 570 | if (HasEntry(title_id, ContentRecordType::Meta)) { | ||
| 571 | LOG_INFO(Loader, | ||
| 572 | "Previously installed entry (v{}) for title_id={:016X} detected! " | ||
| 573 | "Attempting to remove...", | ||
| 574 | GetEntryVersion(title_id).value_or(0), title_id); | ||
| 575 | // Get all the ncas associated with the current CNMT and delete them | ||
| 576 | const auto meta_old_id = | ||
| 577 | GetNcaIDFromMetadata(title_id, ContentRecordType::Meta).value_or(NcaID{}); | ||
| 578 | const auto program_id = | ||
| 579 | GetNcaIDFromMetadata(title_id, ContentRecordType::Program).value_or(NcaID{}); | ||
| 580 | const auto data_id = | ||
| 581 | GetNcaIDFromMetadata(title_id, ContentRecordType::Data).value_or(NcaID{}); | ||
| 582 | const auto control_id = | ||
| 583 | GetNcaIDFromMetadata(title_id, ContentRecordType::Control).value_or(NcaID{}); | ||
| 584 | const auto html_id = | ||
| 585 | GetNcaIDFromMetadata(title_id, ContentRecordType::HtmlDocument).value_or(NcaID{}); | ||
| 586 | const auto legal_id = | ||
| 587 | GetNcaIDFromMetadata(title_id, ContentRecordType::LegalInformation).value_or(NcaID{}); | ||
| 588 | |||
| 589 | delete_nca(meta_old_id); | ||
| 590 | delete_nca(program_id); | ||
| 591 | delete_nca(data_id); | ||
| 592 | delete_nca(control_id); | ||
| 593 | delete_nca(html_id); | ||
| 594 | delete_nca(legal_id); | ||
| 595 | return true; | ||
| 596 | } | ||
| 597 | return false; | ||
| 598 | } | ||
| 599 | |||
| 550 | InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists, | 600 | InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists, |
| 551 | const VfsCopyFunction& copy) { | 601 | const VfsCopyFunction& copy) { |
| 552 | const auto ncas = nsp.GetNCAsCollapsed(); | 602 | const auto ncas = nsp.GetNCAsCollapsed(); |
| @@ -560,31 +610,57 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex | |||
| 560 | return InstallResult::ErrorMetaFailed; | 610 | return InstallResult::ErrorMetaFailed; |
| 561 | } | 611 | } |
| 562 | 612 | ||
| 563 | // Install Metadata File | ||
| 564 | const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); | 613 | const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); |
| 565 | const auto meta_id = Common::HexStringToArray<16>(meta_id_raw); | 614 | const auto meta_id = Common::HexStringToArray<16>(meta_id_raw); |
| 566 | 615 | ||
| 567 | const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id); | 616 | if ((*meta_iter)->GetSubdirectories().empty()) { |
| 568 | if (res != InstallResult::Success) | 617 | LOG_ERROR(Loader, |
| 569 | return res; | 618 | "The file you are attempting to install does not contain a section0 within the " |
| 619 | "metadata NCA and is therefore malformed. Verify that the file is valid."); | ||
| 620 | return InstallResult::ErrorMetaFailed; | ||
| 621 | } | ||
| 570 | 622 | ||
| 571 | // Install all the other NCAs | ||
| 572 | const auto section0 = (*meta_iter)->GetSubdirectories()[0]; | 623 | const auto section0 = (*meta_iter)->GetSubdirectories()[0]; |
| 624 | |||
| 625 | if (section0->GetFiles().empty()) { | ||
| 626 | LOG_ERROR(Loader, | ||
| 627 | "The file you are attempting to install does not contain a CNMT within the " | ||
| 628 | "metadata NCA and is therefore malformed. Verify that the file is valid."); | ||
| 629 | return InstallResult::ErrorMetaFailed; | ||
| 630 | } | ||
| 631 | |||
| 573 | const auto cnmt_file = section0->GetFiles()[0]; | 632 | const auto cnmt_file = section0->GetFiles()[0]; |
| 574 | const CNMT cnmt(cnmt_file); | 633 | const CNMT cnmt(cnmt_file); |
| 634 | |||
| 635 | const auto title_id = cnmt.GetTitleID(); | ||
| 636 | const auto result = RemoveExistingEntry(title_id); | ||
| 637 | |||
| 638 | // Install Metadata File | ||
| 639 | const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id); | ||
| 640 | if (res != InstallResult::Success) { | ||
| 641 | return res; | ||
| 642 | } | ||
| 643 | |||
| 644 | // Install all the other NCAs | ||
| 575 | for (const auto& record : cnmt.GetContentRecords()) { | 645 | for (const auto& record : cnmt.GetContentRecords()) { |
| 576 | // Ignore DeltaFragments, they are not useful to us | 646 | // Ignore DeltaFragments, they are not useful to us |
| 577 | if (record.type == ContentRecordType::DeltaFragment) | 647 | if (record.type == ContentRecordType::DeltaFragment) { |
| 578 | continue; | 648 | continue; |
| 649 | } | ||
| 579 | const auto nca = GetNCAFromNSPForID(nsp, record.nca_id); | 650 | const auto nca = GetNCAFromNSPForID(nsp, record.nca_id); |
| 580 | if (nca == nullptr) | 651 | if (nca == nullptr) { |
| 581 | return InstallResult::ErrorCopyFailed; | 652 | return InstallResult::ErrorCopyFailed; |
| 653 | } | ||
| 582 | const auto res2 = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id); | 654 | const auto res2 = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id); |
| 583 | if (res2 != InstallResult::Success) | 655 | if (res2 != InstallResult::Success) { |
| 584 | return res2; | 656 | return res2; |
| 657 | } | ||
| 585 | } | 658 | } |
| 586 | 659 | ||
| 587 | Refresh(); | 660 | Refresh(); |
| 661 | if (result) { | ||
| 662 | return InstallResult::OverwriteExisting; | ||
| 663 | } | ||
| 588 | return InstallResult::Success; | 664 | return InstallResult::Success; |
| 589 | } | 665 | } |
| 590 | 666 | ||
| @@ -610,8 +686,9 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type, | |||
| 610 | mbedtls_sha256_ret(data.data(), data.size(), c_rec.hash.data(), 0); | 686 | mbedtls_sha256_ret(data.data(), data.size(), c_rec.hash.data(), 0); |
| 611 | memcpy(&c_rec.nca_id, &c_rec.hash, 16); | 687 | memcpy(&c_rec.nca_id, &c_rec.hash, 16); |
| 612 | const CNMT new_cnmt(header, opt_header, {c_rec}, {}); | 688 | const CNMT new_cnmt(header, opt_header, {c_rec}, {}); |
| 613 | if (!RawInstallYuzuMeta(new_cnmt)) | 689 | if (!RawInstallYuzuMeta(new_cnmt)) { |
| 614 | return InstallResult::ErrorMetaFailed; | 690 | return InstallResult::ErrorMetaFailed; |
| 691 | } | ||
| 615 | return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id); | 692 | return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id); |
| 616 | } | 693 | } |
| 617 | 694 | ||
| @@ -649,8 +726,9 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti | |||
| 649 | } | 726 | } |
| 650 | 727 | ||
| 651 | auto out = dir->CreateFileRelative(path); | 728 | auto out = dir->CreateFileRelative(path); |
| 652 | if (out == nullptr) | 729 | if (out == nullptr) { |
| 653 | return InstallResult::ErrorCopyFailed; | 730 | return InstallResult::ErrorCopyFailed; |
| 731 | } | ||
| 654 | return copy(in, out, VFS_RC_LARGE_COPY_BLOCK) ? InstallResult::Success | 732 | return copy(in, out, VFS_RC_LARGE_COPY_BLOCK) ? InstallResult::Success |
| 655 | : InstallResult::ErrorCopyFailed; | 733 | : InstallResult::ErrorCopyFailed; |
| 656 | } | 734 | } |
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 | |||
| 34 | 34 | ||
| 35 | enum class InstallResult { | 35 | enum class InstallResult { |
| 36 | Success, | 36 | Success, |
| 37 | OverwriteExisting, | ||
| 37 | ErrorAlreadyExists, | 38 | ErrorAlreadyExists, |
| 38 | ErrorCopyFailed, | 39 | ErrorCopyFailed, |
| 39 | ErrorMetaFailed, | 40 | ErrorMetaFailed, |
| @@ -154,6 +155,9 @@ public: | |||
| 154 | std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {}, | 155 | std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {}, |
| 155 | std::optional<u64> title_id = {}) const override; | 156 | std::optional<u64> title_id = {}) const override; |
| 156 | 157 | ||
| 158 | // Removes an existing entry based on title id | ||
| 159 | bool RemoveExistingEntry(u64 title_id); | ||
| 160 | |||
| 157 | // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure | 161 | // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure |
| 158 | // there is a meta NCA and all of them are accessible. | 162 | // there is a meta NCA and all of them are accessible. |
| 159 | InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false, | 163 | 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 @@ | |||
| 10 | 10 | ||
| 11 | namespace FileSys { | 11 | namespace FileSys { |
| 12 | 12 | ||
| 13 | constexpr u64 SDMC_TOTAL_SIZE = 0x10000000000; // 1 TiB | ||
| 14 | |||
| 13 | SDMCFactory::SDMCFactory(VirtualDir dir_) | 15 | SDMCFactory::SDMCFactory(VirtualDir dir_) |
| 14 | : dir(std::move(dir_)), contents(std::make_unique<RegisteredCache>( | 16 | : dir(std::move(dir_)), contents(std::make_unique<RegisteredCache>( |
| 15 | GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"), | 17 | GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"), |
| @@ -46,7 +48,7 @@ u64 SDMCFactory::GetSDMCFreeSpace() const { | |||
| 46 | } | 48 | } |
| 47 | 49 | ||
| 48 | u64 SDMCFactory::GetSDMCTotalSpace() const { | 50 | u64 SDMCFactory::GetSDMCTotalSpace() const { |
| 49 | return static_cast<u64>(Settings::values.sdmc_size); | 51 | return SDMC_TOTAL_SIZE; |
| 50 | } | 52 | } |
| 51 | 53 | ||
| 52 | } // namespace FileSys | 54 | } // namespace FileSys |
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 @@ | |||
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/kernel/errors.h" | 9 | #include "core/hle/kernel/errors.h" |
| 10 | #include "core/hle/kernel/handle_table.h" | 10 | #include "core/hle/kernel/handle_table.h" |
| 11 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/process.h" | 12 | #include "core/hle/kernel/process.h" |
| 13 | #include "core/hle/kernel/scheduler.h" | ||
| 12 | #include "core/hle/kernel/thread.h" | 14 | #include "core/hle/kernel/thread.h" |
| 13 | 15 | ||
| 14 | namespace Kernel { | 16 | namespace Kernel { |
| @@ -22,7 +24,7 @@ constexpr u16 GetGeneration(Handle handle) { | |||
| 22 | } | 24 | } |
| 23 | } // Anonymous namespace | 25 | } // Anonymous namespace |
| 24 | 26 | ||
| 25 | HandleTable::HandleTable() { | 27 | HandleTable::HandleTable(KernelCore& kernel) : kernel{kernel} { |
| 26 | Clear(); | 28 | Clear(); |
| 27 | } | 29 | } |
| 28 | 30 | ||
| @@ -103,9 +105,9 @@ bool HandleTable::IsValid(Handle handle) const { | |||
| 103 | 105 | ||
| 104 | std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const { | 106 | std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const { |
| 105 | if (handle == CurrentThread) { | 107 | if (handle == CurrentThread) { |
| 106 | return SharedFrom(GetCurrentThread()); | 108 | return SharedFrom(kernel.CurrentScheduler().GetCurrentThread()); |
| 107 | } else if (handle == CurrentProcess) { | 109 | } else if (handle == CurrentProcess) { |
| 108 | return SharedFrom(Core::System::GetInstance().CurrentProcess()); | 110 | return SharedFrom(kernel.CurrentProcess()); |
| 109 | } | 111 | } |
| 110 | 112 | ||
| 111 | if (!IsValid(handle)) { | 113 | 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 @@ | |||
| 14 | 14 | ||
| 15 | namespace Kernel { | 15 | namespace Kernel { |
| 16 | 16 | ||
| 17 | class KernelCore; | ||
| 18 | |||
| 17 | enum KernelHandle : Handle { | 19 | enum KernelHandle : Handle { |
| 18 | InvalidHandle = 0, | 20 | InvalidHandle = 0, |
| 19 | CurrentThread = 0xFFFF8000, | 21 | CurrentThread = 0xFFFF8000, |
| @@ -48,7 +50,7 @@ public: | |||
| 48 | /// This is the maximum limit of handles allowed per process in Horizon | 50 | /// This is the maximum limit of handles allowed per process in Horizon |
| 49 | static constexpr std::size_t MAX_COUNT = 1024; | 51 | static constexpr std::size_t MAX_COUNT = 1024; |
| 50 | 52 | ||
| 51 | HandleTable(); | 53 | explicit HandleTable(KernelCore& kernel); |
| 52 | ~HandleTable(); | 54 | ~HandleTable(); |
| 53 | 55 | ||
| 54 | /** | 56 | /** |
| @@ -134,6 +136,9 @@ private: | |||
| 134 | 136 | ||
| 135 | /// Head of the free slots linked list. | 137 | /// Head of the free slots linked list. |
| 136 | u16 next_free_slot = 0; | 138 | u16 next_free_slot = 0; |
| 139 | |||
| 140 | /// Underlying kernel instance that this handle table operates under. | ||
| 141 | KernelCore& kernel; | ||
| 137 | }; | 142 | }; |
| 138 | 143 | ||
| 139 | } // namespace Kernel | 144 | } // 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 { | |||
| 50 | 50 | ||
| 51 | struct KernelCore::Impl { | 51 | struct KernelCore::Impl { |
| 52 | explicit Impl(Core::System& system, KernelCore& kernel) | 52 | explicit Impl(Core::System& system, KernelCore& kernel) |
| 53 | : global_scheduler{kernel}, synchronization{system}, time_manager{system}, system{system} {} | 53 | : global_scheduler{kernel}, synchronization{system}, time_manager{system}, |
| 54 | global_handle_table{kernel}, system{system} {} | ||
| 54 | 55 | ||
| 55 | void SetMulticore(bool is_multicore) { | 56 | void SetMulticore(bool is_multicore) { |
| 56 | this->is_multicore = is_multicore; | 57 | this->is_multicore = is_multicore; |
| @@ -160,13 +161,14 @@ struct KernelCore::Impl { | |||
| 160 | void InitializeSuspendThreads() { | 161 | void InitializeSuspendThreads() { |
| 161 | for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { | 162 | for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { |
| 162 | std::string name = "Suspend Thread Id:" + std::to_string(i); | 163 | std::string name = "Suspend Thread Id:" + std::to_string(i); |
| 163 | std::function<void(void*)> init_func = | 164 | std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc(); |
| 164 | system.GetCpuManager().GetSuspendThreadStartFunc(); | ||
| 165 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); | 165 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); |
| 166 | ThreadType type = | 166 | const auto type = |
| 167 | static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_SUSPEND); | 167 | static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_SUSPEND); |
| 168 | auto thread_res = Thread::Create(system, type, name, 0, 0, 0, static_cast<u32>(i), 0, | 168 | auto thread_res = |
| 169 | nullptr, std::move(init_func), init_func_parameter); | 169 | Thread::Create(system, type, std::move(name), 0, 0, 0, static_cast<u32>(i), 0, |
| 170 | nullptr, std::move(init_func), init_func_parameter); | ||
| 171 | |||
| 170 | suspend_threads[i] = std::move(thread_res).Unwrap(); | 172 | suspend_threads[i] = std::move(thread_res).Unwrap(); |
| 171 | } | 173 | } |
| 172 | } | 174 | } |
| @@ -307,7 +309,7 @@ struct KernelCore::Impl { | |||
| 307 | 309 | ||
| 308 | // This is the kernel's handle table or supervisor handle table which | 310 | // This is the kernel's handle table or supervisor handle table which |
| 309 | // stores all the objects in place. | 311 | // stores all the objects in place. |
| 310 | Kernel::HandleTable global_handle_table; | 312 | HandleTable global_handle_table; |
| 311 | 313 | ||
| 312 | /// Map of named ports managed by the kernel, which can be retrieved using | 314 | /// Map of named ports managed by the kernel, which can be retrieved using |
| 313 | /// the ConnectToPort SVC. | 315 | /// 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 @@ | |||
| 9 | #include <string> | 9 | #include <string> |
| 10 | #include <unordered_map> | 10 | #include <unordered_map> |
| 11 | #include <vector> | 11 | #include <vector> |
| 12 | #include "core/arm/cpu_interrupt_handler.h" | ||
| 12 | #include "core/hardware_properties.h" | 13 | #include "core/hardware_properties.h" |
| 13 | #include "core/hle/kernel/memory/memory_types.h" | 14 | #include "core/hle/kernel/memory/memory_types.h" |
| 14 | #include "core/hle/kernel/object.h" | 15 | #include "core/hle/kernel/object.h" |
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: | |||
| 66 | const MemoryRegion application; | 66 | const MemoryRegion application; |
| 67 | const MemoryRegion applet; | 67 | const MemoryRegion applet; |
| 68 | const MemoryRegion system; | 68 | const MemoryRegion system; |
| 69 | |||
| 70 | const PAddr start_address{}; | ||
| 71 | }; | 69 | }; |
| 72 | 70 | ||
| 73 | } // namespace Kernel::Memory | 71 | } // 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) { | |||
| 408 | Process::Process(Core::System& system) | 408 | Process::Process(Core::System& system) |
| 409 | : SynchronizationObject{system.Kernel()}, page_table{std::make_unique<Memory::PageTable>( | 409 | : SynchronizationObject{system.Kernel()}, page_table{std::make_unique<Memory::PageTable>( |
| 410 | system)}, | 410 | system)}, |
| 411 | address_arbiter{system}, mutex{system}, system{system} {} | 411 | handle_table{system.Kernel()}, address_arbiter{system}, mutex{system}, system{system} {} |
| 412 | 412 | ||
| 413 | Process::~Process() = default; | 413 | Process::~Process() = default; |
| 414 | 414 | ||
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: | |||
| 382 | /// List of threads waiting for a condition variable | 382 | /// List of threads waiting for a condition variable |
| 383 | std::unordered_map<VAddr, std::list<std::shared_ptr<Thread>>> cond_var_threads; | 383 | std::unordered_map<VAddr, std::list<std::shared_ptr<Thread>>> cond_var_threads; |
| 384 | 384 | ||
| 385 | /// System context | ||
| 386 | Core::System& system; | ||
| 387 | |||
| 388 | /// Name of this process | ||
| 389 | std::string name; | ||
| 390 | |||
| 391 | /// Address of the top of the main thread's stack | 385 | /// Address of the top of the main thread's stack |
| 392 | VAddr main_thread_stack_top{}; | 386 | VAddr main_thread_stack_top{}; |
| 393 | 387 | ||
| @@ -399,6 +393,12 @@ private: | |||
| 399 | 393 | ||
| 400 | /// Process total image size | 394 | /// Process total image size |
| 401 | std::size_t image_size{}; | 395 | std::size_t image_size{}; |
| 396 | |||
| 397 | /// Name of this process | ||
| 398 | std::string name; | ||
| 399 | |||
| 400 | /// System context | ||
| 401 | Core::System& system; | ||
| 402 | }; | 402 | }; |
| 403 | 403 | ||
| 404 | } // namespace Kernel | 404 | } // 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) { | |||
| 802 | 802 | ||
| 803 | void Scheduler::Initialize() { | 803 | void Scheduler::Initialize() { |
| 804 | std::string name = "Idle Thread Id:" + std::to_string(core_id); | 804 | std::string name = "Idle Thread Id:" + std::to_string(core_id); |
| 805 | std::function<void(void*)> init_func = system.GetCpuManager().GetIdleThreadStartFunc(); | 805 | std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc(); |
| 806 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); | 806 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); |
| 807 | ThreadType type = static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE); | 807 | ThreadType type = static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE); |
| 808 | auto thread_res = Thread::Create(system, type, name, 0, 64, 0, static_cast<u32>(core_id), 0, | 808 | 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 @@ | |||
| 13 | #include "common/logging/log.h" | 13 | #include "common/logging/log.h" |
| 14 | #include "common/thread_queue_list.h" | 14 | #include "common/thread_queue_list.h" |
| 15 | #include "core/arm/arm_interface.h" | 15 | #include "core/arm/arm_interface.h" |
| 16 | #ifdef ARCHITECTURE_x86_64 | ||
| 17 | #include "core/arm/dynarmic/arm_dynarmic_32.h" | ||
| 18 | #include "core/arm/dynarmic/arm_dynarmic_64.h" | ||
| 19 | #endif | ||
| 20 | #include "core/arm/cpu_interrupt_handler.h" | ||
| 21 | #include "core/arm/exclusive_monitor.h" | ||
| 22 | #include "core/arm/unicorn/arm_unicorn.h" | 16 | #include "core/arm/unicorn/arm_unicorn.h" |
| 23 | #include "core/core.h" | 17 | #include "core/core.h" |
| 24 | #include "core/core_timing.h" | ||
| 25 | #include "core/core_timing_util.h" | ||
| 26 | #include "core/cpu_manager.h" | 18 | #include "core/cpu_manager.h" |
| 27 | #include "core/hardware_properties.h" | 19 | #include "core/hardware_properties.h" |
| 28 | #include "core/hle/kernel/errors.h" | 20 | #include "core/hle/kernel/errors.h" |
| @@ -36,6 +28,11 @@ | |||
| 36 | #include "core/hle/result.h" | 28 | #include "core/hle/result.h" |
| 37 | #include "core/memory.h" | 29 | #include "core/memory.h" |
| 38 | 30 | ||
| 31 | #ifdef ARCHITECTURE_x86_64 | ||
| 32 | #include "core/arm/dynarmic/arm_dynarmic_32.h" | ||
| 33 | #include "core/arm/dynarmic/arm_dynarmic_64.h" | ||
| 34 | #endif | ||
| 35 | |||
| 39 | namespace Kernel { | 36 | namespace Kernel { |
| 40 | 37 | ||
| 41 | bool Thread::ShouldWait(const Thread* thread) const { | 38 | bool Thread::ShouldWait(const Thread* thread) const { |
| @@ -158,7 +155,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy | |||
| 158 | std::string name, VAddr entry_point, u32 priority, | 155 | std::string name, VAddr entry_point, u32 priority, |
| 159 | u64 arg, s32 processor_id, VAddr stack_top, | 156 | u64 arg, s32 processor_id, VAddr stack_top, |
| 160 | Process* owner_process) { | 157 | Process* owner_process) { |
| 161 | std::function<void(void*)> init_func = system.GetCpuManager().GetGuestThreadStartFunc(); | 158 | std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc(); |
| 162 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); | 159 | void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); |
| 163 | return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top, | 160 | return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top, |
| 164 | owner_process, std::move(init_func), init_func_parameter); | 161 | owner_process, std::move(init_func), init_func_parameter); |
| @@ -540,13 +537,4 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { | |||
| 540 | return RESULT_SUCCESS; | 537 | return RESULT_SUCCESS; |
| 541 | } | 538 | } |
| 542 | 539 | ||
| 543 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 544 | |||
| 545 | /** | ||
| 546 | * Gets the current thread | ||
| 547 | */ | ||
| 548 | Thread* GetCurrentThread() { | ||
| 549 | return Core::System::GetInstance().CurrentScheduler().GetCurrentThread(); | ||
| 550 | } | ||
| 551 | |||
| 552 | } // namespace Kernel | 540 | } // 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: | |||
| 680 | std::string name; | 680 | std::string name; |
| 681 | }; | 681 | }; |
| 682 | 682 | ||
| 683 | /** | ||
| 684 | * Gets the current thread | ||
| 685 | */ | ||
| 686 | Thread* GetCurrentThread(); | ||
| 687 | |||
| 688 | } // namespace Kernel | 683 | } // namespace Kernel |
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() { | |||
| 184 | values.sound_index.SetGlobal(true); | 184 | values.sound_index.SetGlobal(true); |
| 185 | } | 185 | } |
| 186 | 186 | ||
| 187 | void Sanitize() { | ||
| 188 | values.use_asynchronous_gpu_emulation.SetValue( | ||
| 189 | values.use_asynchronous_gpu_emulation.GetValue() || values.use_multi_core.GetValue()); | ||
| 190 | } | ||
| 191 | |||
| 187 | } // namespace Settings | 192 | } // 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 { | |||
| 346 | u32 rotation_angle; | 346 | u32 rotation_angle; |
| 347 | }; | 347 | }; |
| 348 | 348 | ||
| 349 | enum class NANDTotalSize : u64 { | ||
| 350 | S29_1GB = 0x747C00000ULL, | ||
| 351 | }; | ||
| 352 | |||
| 353 | enum class NANDUserSize : u64 { | ||
| 354 | S26GB = 0x680000000ULL, | ||
| 355 | }; | ||
| 356 | |||
| 357 | enum class NANDSystemSize : u64 { | ||
| 358 | S2_5GB = 0xA0000000, | ||
| 359 | }; | ||
| 360 | |||
| 361 | enum class SDMCSize : u64 { | ||
| 362 | S1GB = 0x40000000, | ||
| 363 | S2GB = 0x80000000, | ||
| 364 | S4GB = 0x100000000ULL, | ||
| 365 | S8GB = 0x200000000ULL, | ||
| 366 | S16GB = 0x400000000ULL, | ||
| 367 | S32GB = 0x800000000ULL, | ||
| 368 | S64GB = 0x1000000000ULL, | ||
| 369 | S128GB = 0x2000000000ULL, | ||
| 370 | S256GB = 0x4000000000ULL, | ||
| 371 | S1TB = 0x10000000000ULL, | ||
| 372 | }; | ||
| 373 | |||
| 374 | enum class RendererBackend { | 349 | enum class RendererBackend { |
| 375 | OpenGL = 0, | 350 | OpenGL = 0, |
| 376 | Vulkan = 1, | 351 | Vulkan = 1, |
| @@ -382,6 +357,11 @@ enum class GPUAccuracy : u32 { | |||
| 382 | Extreme = 2, | 357 | Extreme = 2, |
| 383 | }; | 358 | }; |
| 384 | 359 | ||
| 360 | enum class CPUAccuracy { | ||
| 361 | Accurate = 0, | ||
| 362 | DebugMode = 1, | ||
| 363 | }; | ||
| 364 | |||
| 385 | extern bool configuring_global; | 365 | extern bool configuring_global; |
| 386 | 366 | ||
| 387 | template <typename Type> | 367 | template <typename Type> |
| @@ -427,6 +407,18 @@ struct Values { | |||
| 427 | // Core | 407 | // Core |
| 428 | Setting<bool> use_multi_core; | 408 | Setting<bool> use_multi_core; |
| 429 | 409 | ||
| 410 | // Cpu | ||
| 411 | CPUAccuracy cpu_accuracy; | ||
| 412 | |||
| 413 | bool cpuopt_page_tables; | ||
| 414 | bool cpuopt_block_linking; | ||
| 415 | bool cpuopt_return_stack_buffer; | ||
| 416 | bool cpuopt_fast_dispatcher; | ||
| 417 | bool cpuopt_context_elimination; | ||
| 418 | bool cpuopt_const_prop; | ||
| 419 | bool cpuopt_misc_ir; | ||
| 420 | bool cpuopt_reduce_misalign_checks; | ||
| 421 | |||
| 430 | // Renderer | 422 | // Renderer |
| 431 | Setting<RendererBackend> renderer_backend; | 423 | Setting<RendererBackend> renderer_backend; |
| 432 | bool renderer_debug; | 424 | bool renderer_debug; |
| @@ -491,10 +483,6 @@ struct Values { | |||
| 491 | bool gamecard_inserted; | 483 | bool gamecard_inserted; |
| 492 | bool gamecard_current_game; | 484 | bool gamecard_current_game; |
| 493 | std::string gamecard_path; | 485 | std::string gamecard_path; |
| 494 | NANDTotalSize nand_total_size; | ||
| 495 | NANDSystemSize nand_system_size; | ||
| 496 | NANDUserSize nand_user_size; | ||
| 497 | SDMCSize sdmc_size; | ||
| 498 | 486 | ||
| 499 | // Debugging | 487 | // Debugging |
| 500 | bool record_frame_times; | 488 | bool record_frame_times; |
| @@ -505,7 +493,6 @@ struct Values { | |||
| 505 | bool dump_nso; | 493 | bool dump_nso; |
| 506 | bool reporting_services; | 494 | bool reporting_services; |
| 507 | bool quest_flag; | 495 | bool quest_flag; |
| 508 | bool disable_cpu_opt; | ||
| 509 | bool disable_macro_jit; | 496 | bool disable_macro_jit; |
| 510 | 497 | ||
| 511 | // Misceallaneous | 498 | // Misceallaneous |
| @@ -539,4 +526,7 @@ void LogSettings(); | |||
| 539 | // Restore the global state of all applicable settings in the Values struct | 526 | // Restore the global state of all applicable settings in the Values struct |
| 540 | void RestoreGlobalState(); | 527 | void RestoreGlobalState(); |
| 541 | 528 | ||
| 529 | // Fixes settings that are known to cause issues with the emulator | ||
| 530 | void Sanitize(); | ||
| 531 | |||
| 542 | } // namespace Settings | 532 | } // 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) | |||
| 30 | target_compile_definitions(input_common PRIVATE HAVE_SDL2) | 30 | target_compile_definitions(input_common PRIVATE HAVE_SDL2) |
| 31 | endif() | 31 | endif() |
| 32 | 32 | ||
| 33 | target_link_libraries(input_common PUBLIC ${LIBUSB_LIBRARIES}) | 33 | target_include_directories(input_common SYSTEM PRIVATE ${LIBUSB_INCLUDE_DIR}) |
| 34 | target_link_libraries(input_common PRIVATE ${LIBUSB_LIBRARIES}) | ||
| 34 | 35 | ||
| 35 | create_target_directory_groups(input_common) | 36 | create_target_directory_groups(input_common) |
| 36 | target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost) | 37 | 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 @@ | |||
| 4 | 4 | ||
| 5 | #include <chrono> | 5 | #include <chrono> |
| 6 | #include <thread> | 6 | #include <thread> |
| 7 | #include <libusb.h> | ||
| 7 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 8 | #include "input_common/gcadapter/gc_adapter.h" | 9 | #include "input_common/gcadapter/gc_adapter.h" |
| 9 | 10 | ||
| @@ -24,6 +25,7 @@ Adapter::Adapter() { | |||
| 24 | LOG_INFO(Input, "GC Adapter Initialization started"); | 25 | LOG_INFO(Input, "GC Adapter Initialization started"); |
| 25 | 26 | ||
| 26 | current_status = NO_ADAPTER_DETECTED; | 27 | current_status = NO_ADAPTER_DETECTED; |
| 28 | get_origin.fill(true); | ||
| 27 | 29 | ||
| 28 | const int init_res = libusb_init(&libusb_ctx); | 30 | const int init_res = libusb_init(&libusb_ctx); |
| 29 | if (init_res == LIBUSB_SUCCESS) { | 31 | if (init_res == LIBUSB_SUCCESS) { |
| @@ -33,15 +35,10 @@ Adapter::Adapter() { | |||
| 33 | } | 35 | } |
| 34 | } | 36 | } |
| 35 | 37 | ||
| 36 | GCPadStatus Adapter::GetPadStatus(int port, const std::array<u8, 37>& adapter_payload) { | 38 | GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload) { |
| 37 | GCPadStatus pad = {}; | 39 | GCPadStatus pad = {}; |
| 38 | bool get_origin = false; | ||
| 39 | 40 | ||
| 40 | ControllerTypes type = ControllerTypes(adapter_payload[1 + (9 * port)] >> 4); | 41 | ControllerTypes type = ControllerTypes(adapter_payload[1 + (9 * port)] >> 4); |
| 41 | if (type != ControllerTypes::None) { | ||
| 42 | get_origin = true; | ||
| 43 | } | ||
| 44 | |||
| 45 | adapter_controllers_status[port] = type; | 42 | adapter_controllers_status[port] = type; |
| 46 | 43 | ||
| 47 | static constexpr std::array<PadButton, 8> b1_buttons{ | 44 | static constexpr std::array<PadButton, 8> b1_buttons{ |
| @@ -57,6 +54,11 @@ GCPadStatus Adapter::GetPadStatus(int port, const std::array<u8, 37>& adapter_pa | |||
| 57 | PadButton::PAD_TRIGGER_L, | 54 | PadButton::PAD_TRIGGER_L, |
| 58 | }; | 55 | }; |
| 59 | 56 | ||
| 57 | if (adapter_controllers_status[port] == ControllerTypes::None && !get_origin[port]) { | ||
| 58 | // Controller may have been disconnected, recalibrate if reconnected. | ||
| 59 | get_origin[port] = true; | ||
| 60 | } | ||
| 61 | |||
| 60 | if (adapter_controllers_status[port] != ControllerTypes::None) { | 62 | if (adapter_controllers_status[port] != ControllerTypes::None) { |
| 61 | const u8 b1 = adapter_payload[1 + (9 * port) + 1]; | 63 | const u8 b1 = adapter_payload[1 + (9 * port) + 1]; |
| 62 | const u8 b2 = adapter_payload[1 + (9 * port) + 2]; | 64 | 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 | |||
| 73 | } | 75 | } |
| 74 | } | 76 | } |
| 75 | 77 | ||
| 76 | if (get_origin) { | ||
| 77 | pad.button |= PAD_GET_ORIGIN; | ||
| 78 | } | ||
| 79 | |||
| 80 | pad.stick_x = adapter_payload[1 + (9 * port) + 3]; | 78 | pad.stick_x = adapter_payload[1 + (9 * port) + 3]; |
| 81 | pad.stick_y = adapter_payload[1 + (9 * port) + 4]; | 79 | pad.stick_y = adapter_payload[1 + (9 * port) + 4]; |
| 82 | pad.substick_x = adapter_payload[1 + (9 * port) + 5]; | 80 | pad.substick_x = adapter_payload[1 + (9 * port) + 5]; |
| 83 | pad.substick_y = adapter_payload[1 + (9 * port) + 6]; | 81 | pad.substick_y = adapter_payload[1 + (9 * port) + 6]; |
| 84 | pad.trigger_left = adapter_payload[1 + (9 * port) + 7]; | 82 | pad.trigger_left = adapter_payload[1 + (9 * port) + 7]; |
| 85 | pad.trigger_right = adapter_payload[1 + (9 * port) + 8]; | 83 | pad.trigger_right = adapter_payload[1 + (9 * port) + 8]; |
| 84 | |||
| 85 | if (get_origin[port]) { | ||
| 86 | origin_status[port].stick_x = pad.stick_x; | ||
| 87 | origin_status[port].stick_y = pad.stick_y; | ||
| 88 | origin_status[port].substick_x = pad.substick_x; | ||
| 89 | origin_status[port].substick_y = pad.substick_y; | ||
| 90 | origin_status[port].trigger_left = pad.trigger_left; | ||
| 91 | origin_status[port].trigger_right = pad.trigger_right; | ||
| 92 | get_origin[port] = false; | ||
| 93 | } | ||
| 86 | } | 94 | } |
| 87 | return pad; | 95 | return pad; |
| 88 | } | 96 | } |
| @@ -131,31 +139,31 @@ void Adapter::Read() { | |||
| 131 | for (std::size_t port = 0; port < pads.size(); ++port) { | 139 | for (std::size_t port = 0; port < pads.size(); ++port) { |
| 132 | pads[port] = GetPadStatus(port, adapter_payload_copy); | 140 | pads[port] = GetPadStatus(port, adapter_payload_copy); |
| 133 | if (DeviceConnected(port) && configuring) { | 141 | if (DeviceConnected(port) && configuring) { |
| 134 | if (pads[port].button != PAD_GET_ORIGIN) { | 142 | if (pads[port].button != 0) { |
| 135 | pad_queue[port].Push(pads[port]); | 143 | pad_queue[port].Push(pads[port]); |
| 136 | } | 144 | } |
| 137 | 145 | ||
| 138 | // Accounting for a threshold here because of some controller variance | 146 | // Accounting for a threshold here because of some controller variance |
| 139 | if (pads[port].stick_x > pads[port].MAIN_STICK_CENTER_X + pads[port].THRESHOLD || | 147 | if (pads[port].stick_x > origin_status[port].stick_x + pads[port].THRESHOLD || |
| 140 | pads[port].stick_x < pads[port].MAIN_STICK_CENTER_X - pads[port].THRESHOLD) { | 148 | pads[port].stick_x < origin_status[port].stick_x - pads[port].THRESHOLD) { |
| 141 | pads[port].axis = GCAdapter::PadAxes::StickX; | 149 | pads[port].axis = GCAdapter::PadAxes::StickX; |
| 142 | pads[port].axis_value = pads[port].stick_x; | 150 | pads[port].axis_value = pads[port].stick_x; |
| 143 | pad_queue[port].Push(pads[port]); | 151 | pad_queue[port].Push(pads[port]); |
| 144 | } | 152 | } |
| 145 | if (pads[port].stick_y > pads[port].MAIN_STICK_CENTER_Y + pads[port].THRESHOLD || | 153 | if (pads[port].stick_y > origin_status[port].stick_y + pads[port].THRESHOLD || |
| 146 | pads[port].stick_y < pads[port].MAIN_STICK_CENTER_Y - pads[port].THRESHOLD) { | 154 | pads[port].stick_y < origin_status[port].stick_y - pads[port].THRESHOLD) { |
| 147 | pads[port].axis = GCAdapter::PadAxes::StickY; | 155 | pads[port].axis = GCAdapter::PadAxes::StickY; |
| 148 | pads[port].axis_value = pads[port].stick_y; | 156 | pads[port].axis_value = pads[port].stick_y; |
| 149 | pad_queue[port].Push(pads[port]); | 157 | pad_queue[port].Push(pads[port]); |
| 150 | } | 158 | } |
| 151 | if (pads[port].substick_x > pads[port].C_STICK_CENTER_X + pads[port].THRESHOLD || | 159 | if (pads[port].substick_x > origin_status[port].substick_x + pads[port].THRESHOLD || |
| 152 | pads[port].substick_x < pads[port].C_STICK_CENTER_X - pads[port].THRESHOLD) { | 160 | pads[port].substick_x < origin_status[port].substick_x - pads[port].THRESHOLD) { |
| 153 | pads[port].axis = GCAdapter::PadAxes::SubstickX; | 161 | pads[port].axis = GCAdapter::PadAxes::SubstickX; |
| 154 | pads[port].axis_value = pads[port].substick_x; | 162 | pads[port].axis_value = pads[port].substick_x; |
| 155 | pad_queue[port].Push(pads[port]); | 163 | pad_queue[port].Push(pads[port]); |
| 156 | } | 164 | } |
| 157 | if (pads[port].substick_y > pads[port].C_STICK_CENTER_Y + pads[port].THRESHOLD || | 165 | if (pads[port].substick_y > origin_status[port].substick_y + pads[port].THRESHOLD || |
| 158 | pads[port].substick_y < pads[port].C_STICK_CENTER_Y - pads[port].THRESHOLD) { | 166 | pads[port].substick_y < origin_status[port].substick_y - pads[port].THRESHOLD) { |
| 159 | pads[port].axis = GCAdapter::PadAxes::SubstickY; | 167 | pads[port].axis = GCAdapter::PadAxes::SubstickY; |
| 160 | pads[port].axis_value = pads[port].substick_y; | 168 | pads[port].axis_value = pads[port].substick_y; |
| 161 | pad_queue[port].Push(pads[port]); | 169 | pad_queue[port].Push(pads[port]); |
| @@ -198,7 +206,7 @@ void Adapter::StartScanThread() { | |||
| 198 | } | 206 | } |
| 199 | 207 | ||
| 200 | detect_thread_running = true; | 208 | detect_thread_running = true; |
| 201 | detect_thread = std::thread([=] { ScanThreadFunc(); }); | 209 | detect_thread = std::thread(&Adapter::ScanThreadFunc, this); |
| 202 | } | 210 | } |
| 203 | 211 | ||
| 204 | void Adapter::StopScanThread() { | 212 | void Adapter::StopScanThread() { |
| @@ -227,7 +235,7 @@ void Adapter::Setup() { | |||
| 227 | } | 235 | } |
| 228 | 236 | ||
| 229 | if (devices != nullptr) { | 237 | if (devices != nullptr) { |
| 230 | for (std::size_t index = 0; index < device_count; ++index) { | 238 | for (std::size_t index = 0; index < static_cast<std::size_t>(device_count); ++index) { |
| 231 | if (CheckDeviceAccess(devices[index])) { | 239 | if (CheckDeviceAccess(devices[index])) { |
| 232 | // GC Adapter found and accessible, registering it | 240 | // GC Adapter found and accessible, registering it |
| 233 | GetGCEndpoint(devices[index]); | 241 | GetGCEndpoint(devices[index]); |
| @@ -236,6 +244,9 @@ void Adapter::Setup() { | |||
| 236 | } | 244 | } |
| 237 | libusb_free_device_list(devices, 1); | 245 | libusb_free_device_list(devices, 1); |
| 238 | } | 246 | } |
| 247 | // Break out of the ScanThreadFunc() loop that is constantly looking for the device | ||
| 248 | // Assumes user has GC adapter plugged in before launch to use the adapter | ||
| 249 | detect_thread_running = false; | ||
| 239 | } | 250 | } |
| 240 | 251 | ||
| 241 | bool Adapter::CheckDeviceAccess(libusb_device* device) { | 252 | bool Adapter::CheckDeviceAccess(libusb_device* device) { |
| @@ -344,6 +355,7 @@ void Adapter::Reset() { | |||
| 344 | adapter_input_thread.join(); | 355 | adapter_input_thread.join(); |
| 345 | 356 | ||
| 346 | adapter_controllers_status.fill(ControllerTypes::None); | 357 | adapter_controllers_status.fill(ControllerTypes::None); |
| 358 | get_origin.fill(true); | ||
| 347 | current_status = NO_ADAPTER_DETECTED; | 359 | current_status = NO_ADAPTER_DETECTED; |
| 348 | 360 | ||
| 349 | if (usb_adapter_handle) { | 361 | if (usb_adapter_handle) { |
| @@ -357,15 +369,16 @@ void Adapter::Reset() { | |||
| 357 | } | 369 | } |
| 358 | } | 370 | } |
| 359 | 371 | ||
| 360 | bool Adapter::DeviceConnected(int port) { | 372 | bool Adapter::DeviceConnected(std::size_t port) { |
| 361 | return adapter_controllers_status[port] != ControllerTypes::None; | 373 | return adapter_controllers_status[port] != ControllerTypes::None; |
| 362 | } | 374 | } |
| 363 | 375 | ||
| 364 | void Adapter::ResetDeviceType(int port) { | 376 | void Adapter::ResetDeviceType(std::size_t port) { |
| 365 | adapter_controllers_status[port] = ControllerTypes::None; | 377 | adapter_controllers_status[port] = ControllerTypes::None; |
| 366 | } | 378 | } |
| 367 | 379 | ||
| 368 | void Adapter::BeginConfiguration() { | 380 | void Adapter::BeginConfiguration() { |
| 381 | get_origin.fill(true); | ||
| 369 | for (auto& pq : pad_queue) { | 382 | for (auto& pq : pad_queue) { |
| 370 | pq.Clear(); | 383 | pq.Clear(); |
| 371 | } | 384 | } |
| @@ -395,4 +408,25 @@ const std::array<GCState, 4>& Adapter::GetPadState() const { | |||
| 395 | return state; | 408 | return state; |
| 396 | } | 409 | } |
| 397 | 410 | ||
| 411 | int Adapter::GetOriginValue(int port, int axis) const { | ||
| 412 | const auto& status = origin_status[port]; | ||
| 413 | |||
| 414 | switch (static_cast<PadAxes>(axis)) { | ||
| 415 | case PadAxes::StickX: | ||
| 416 | return status.stick_x; | ||
| 417 | case PadAxes::StickY: | ||
| 418 | return status.stick_y; | ||
| 419 | case PadAxes::SubstickX: | ||
| 420 | return status.substick_x; | ||
| 421 | case PadAxes::SubstickY: | ||
| 422 | return status.substick_y; | ||
| 423 | case PadAxes::TriggerLeft: | ||
| 424 | return status.trigger_left; | ||
| 425 | case PadAxes::TriggerRight: | ||
| 426 | return status.trigger_right; | ||
| 427 | default: | ||
| 428 | return 0; | ||
| 429 | } | ||
| 430 | } | ||
| 431 | |||
| 398 | } // namespace GCAdapter | 432 | } // 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 @@ | |||
| 8 | #include <mutex> | 8 | #include <mutex> |
| 9 | #include <thread> | 9 | #include <thread> |
| 10 | #include <unordered_map> | 10 | #include <unordered_map> |
| 11 | #include <libusb.h> | ||
| 12 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 13 | #include "common/threadsafe_queue.h" | 12 | #include "common/threadsafe_queue.h" |
| 14 | 13 | ||
| 15 | namespace GCAdapter { | 14 | struct libusb_context; |
| 15 | struct libusb_device; | ||
| 16 | struct libusb_device_handle; | ||
| 16 | 17 | ||
| 17 | enum { | 18 | namespace GCAdapter { |
| 18 | PAD_USE_ORIGIN = 0x0080, | ||
| 19 | PAD_GET_ORIGIN = 0x2000, | ||
| 20 | PAD_ERR_STATUS = 0x8000, | ||
| 21 | }; | ||
| 22 | 19 | ||
| 23 | enum class PadButton { | 20 | enum class PadButton { |
| 24 | PAD_BUTTON_LEFT = 0x0001, | 21 | PAD_BUTTON_LEFT = 0x0001, |
| @@ -97,14 +94,19 @@ public: | |||
| 97 | void BeginConfiguration(); | 94 | void BeginConfiguration(); |
| 98 | void EndConfiguration(); | 95 | void EndConfiguration(); |
| 99 | 96 | ||
| 97 | /// Returns true if there is a device connected to port | ||
| 98 | bool DeviceConnected(std::size_t port); | ||
| 99 | |||
| 100 | std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue(); | 100 | std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue(); |
| 101 | const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const; | 101 | const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const; |
| 102 | 102 | ||
| 103 | std::array<GCState, 4>& GetPadState(); | 103 | std::array<GCState, 4>& GetPadState(); |
| 104 | const std::array<GCState, 4>& GetPadState() const; | 104 | const std::array<GCState, 4>& GetPadState() const; |
| 105 | 105 | ||
| 106 | int GetOriginValue(int port, int axis) const; | ||
| 107 | |||
| 106 | private: | 108 | private: |
| 107 | GCPadStatus GetPadStatus(int port, const std::array<u8, 37>& adapter_payload); | 109 | GCPadStatus GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload); |
| 108 | 110 | ||
| 109 | void PadToState(const GCPadStatus& pad, GCState& state); | 111 | void PadToState(const GCPadStatus& pad, GCState& state); |
| 110 | 112 | ||
| @@ -116,11 +118,8 @@ private: | |||
| 116 | /// Stop scanning for the adapter | 118 | /// Stop scanning for the adapter |
| 117 | void StopScanThread(); | 119 | void StopScanThread(); |
| 118 | 120 | ||
| 119 | /// Returns true if there is a device connected to port | ||
| 120 | bool DeviceConnected(int port); | ||
| 121 | |||
| 122 | /// Resets status of device connected to port | 121 | /// Resets status of device connected to port |
| 123 | void ResetDeviceType(int port); | 122 | void ResetDeviceType(std::size_t port); |
| 124 | 123 | ||
| 125 | /// Returns true if we successfully gain access to GC Adapter | 124 | /// Returns true if we successfully gain access to GC Adapter |
| 126 | bool CheckDeviceAccess(libusb_device* device); | 125 | bool CheckDeviceAccess(libusb_device* device); |
| @@ -156,6 +155,8 @@ private: | |||
| 156 | 155 | ||
| 157 | std::array<Common::SPSCQueue<GCPadStatus>, 4> pad_queue; | 156 | std::array<Common::SPSCQueue<GCPadStatus>, 4> pad_queue; |
| 158 | std::array<GCState, 4> state; | 157 | std::array<GCState, 4> state; |
| 158 | std::array<bool, 4> get_origin; | ||
| 159 | std::array<GCPadStatus, 4> origin_status; | ||
| 159 | }; | 160 | }; |
| 160 | 161 | ||
| 161 | } // namespace GCAdapter | 162 | } // 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 @@ | |||
| 6 | #include <list> | 6 | #include <list> |
| 7 | #include <mutex> | 7 | #include <mutex> |
| 8 | #include <utility> | 8 | #include <utility> |
| 9 | #include "common/assert.h" | ||
| 9 | #include "common/threadsafe_queue.h" | 10 | #include "common/threadsafe_queue.h" |
| 10 | #include "input_common/gcadapter/gc_adapter.h" | 11 | #include "input_common/gcadapter/gc_adapter.h" |
| 11 | #include "input_common/gcadapter/gc_poller.h" | 12 | #include "input_common/gcadapter/gc_poller.h" |
| @@ -20,7 +21,10 @@ public: | |||
| 20 | ~GCButton() override; | 21 | ~GCButton() override; |
| 21 | 22 | ||
| 22 | bool GetStatus() const override { | 23 | bool GetStatus() const override { |
| 23 | return gcadapter->GetPadState()[port].buttons.at(button); | 24 | if (gcadapter->DeviceConnected(port)) { |
| 25 | return gcadapter->GetPadState()[port].buttons.at(button); | ||
| 26 | } | ||
| 27 | return false; | ||
| 24 | } | 28 | } |
| 25 | 29 | ||
| 26 | private: | 30 | private: |
| @@ -34,22 +38,20 @@ public: | |||
| 34 | explicit GCAxisButton(int port_, int axis_, float threshold_, bool trigger_if_greater_, | 38 | explicit GCAxisButton(int port_, int axis_, float threshold_, bool trigger_if_greater_, |
| 35 | GCAdapter::Adapter* adapter) | 39 | GCAdapter::Adapter* adapter) |
| 36 | : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_), | 40 | : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_), |
| 37 | gcadapter(adapter) { | 41 | gcadapter(adapter), origin_value(adapter->GetOriginValue(port_, axis_)) {} |
| 38 | // L/R triggers range is only in positive direction beginning near 0 | ||
| 39 | // 0.0 threshold equates to near half trigger press, but threshold accounts for variability. | ||
| 40 | if (axis > 3) { | ||
| 41 | threshold *= -0.5; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | 42 | ||
| 45 | bool GetStatus() const override { | 43 | bool GetStatus() const override { |
| 46 | const float axis_value = (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 128.0f; | 44 | if (gcadapter->DeviceConnected(port)) { |
| 47 | if (trigger_if_greater) { | 45 | const float current_axis_value = gcadapter->GetPadState()[port].axes.at(axis); |
| 48 | // TODO: Might be worthwile to set a slider for the trigger threshold. It is currently | 46 | const float axis_value = (current_axis_value - origin_value) / 128.0f; |
| 49 | // always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick | 47 | if (trigger_if_greater) { |
| 50 | return axis_value > threshold; | 48 | // TODO: Might be worthwile to set a slider for the trigger threshold. It is |
| 49 | // currently always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick | ||
| 50 | return axis_value > threshold; | ||
| 51 | } | ||
| 52 | return axis_value < -threshold; | ||
| 51 | } | 53 | } |
| 52 | return axis_value < -threshold; | 54 | return false; |
| 53 | } | 55 | } |
| 54 | 56 | ||
| 55 | private: | 57 | private: |
| @@ -58,6 +60,7 @@ private: | |||
| 58 | float threshold; | 60 | float threshold; |
| 59 | bool trigger_if_greater; | 61 | bool trigger_if_greater; |
| 60 | GCAdapter::Adapter* gcadapter; | 62 | GCAdapter::Adapter* gcadapter; |
| 63 | const float origin_value; | ||
| 61 | }; | 64 | }; |
| 62 | 65 | ||
| 63 | GCButtonFactory::GCButtonFactory(std::shared_ptr<GCAdapter::Adapter> adapter_) | 66 | GCButtonFactory::GCButtonFactory(std::shared_ptr<GCAdapter::Adapter> adapter_) |
| @@ -94,9 +97,12 @@ std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::Param | |||
| 94 | return std::make_unique<GCAxisButton>(port, axis, threshold, trigger_if_greater, | 97 | return std::make_unique<GCAxisButton>(port, axis, threshold, trigger_if_greater, |
| 95 | adapter.get()); | 98 | adapter.get()); |
| 96 | } | 99 | } |
| 100 | |||
| 101 | UNREACHABLE(); | ||
| 102 | return nullptr; | ||
| 97 | } | 103 | } |
| 98 | 104 | ||
| 99 | Common::ParamPackage GCButtonFactory::GetNextInput() { | 105 | Common::ParamPackage GCButtonFactory::GetNextInput() const { |
| 100 | Common::ParamPackage params; | 106 | Common::ParamPackage params; |
| 101 | GCAdapter::GCPadStatus pad; | 107 | GCAdapter::GCPadStatus pad; |
| 102 | auto& queue = adapter->GetPadQueue(); | 108 | auto& queue = adapter->GetPadQueue(); |
| @@ -144,14 +150,20 @@ void GCButtonFactory::EndConfiguration() { | |||
| 144 | class GCAnalog final : public Input::AnalogDevice { | 150 | class GCAnalog final : public Input::AnalogDevice { |
| 145 | public: | 151 | public: |
| 146 | GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter) | 152 | GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter) |
| 147 | : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter) {} | 153 | : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter), |
| 154 | origin_value_x(adapter->GetOriginValue(port_, axis_x_)), | ||
| 155 | origin_value_y(adapter->GetOriginValue(port_, axis_y_)) {} | ||
| 148 | 156 | ||
| 149 | float GetAxis(int axis) const { | 157 | float GetAxis(int axis) const { |
| 150 | std::lock_guard lock{mutex}; | 158 | if (gcadapter->DeviceConnected(port)) { |
| 151 | // division is not by a perfect 128 to account for some variance in center location | 159 | std::lock_guard lock{mutex}; |
| 152 | // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range | 160 | const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y; |
| 153 | // [20-230] | 161 | // division is not by a perfect 128 to account for some variance in center location |
| 154 | return (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 95.0f; | 162 | // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range |
| 163 | // [20-230] | ||
| 164 | return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / 95.0f; | ||
| 165 | } | ||
| 166 | return 0.0f; | ||
| 155 | } | 167 | } |
| 156 | 168 | ||
| 157 | std::pair<float, float> GetAnalog(int axis_x, int axis_y) const { | 169 | std::pair<float, float> GetAnalog(int axis_x, int axis_y) const { |
| @@ -201,8 +213,10 @@ private: | |||
| 201 | const int axis_x; | 213 | const int axis_x; |
| 202 | const int axis_y; | 214 | const int axis_y; |
| 203 | const float deadzone; | 215 | const float deadzone; |
| 204 | mutable std::mutex mutex; | ||
| 205 | GCAdapter::Adapter* gcadapter; | 216 | GCAdapter::Adapter* gcadapter; |
| 217 | const float origin_value_x; | ||
| 218 | const float origin_value_y; | ||
| 219 | mutable std::mutex mutex; | ||
| 206 | }; | 220 | }; |
| 207 | 221 | ||
| 208 | /// An analog device factory that creates analog devices from GC Adapter | 222 | /// An analog device factory that creates analog devices from GC Adapter |
| @@ -249,7 +263,7 @@ Common::ParamPackage GCAnalogFactory::GetNextInput() { | |||
| 249 | const u8 axis = static_cast<u8>(pad.axis); | 263 | const u8 axis = static_cast<u8>(pad.axis); |
| 250 | if (analog_x_axis == -1) { | 264 | if (analog_x_axis == -1) { |
| 251 | analog_x_axis = axis; | 265 | analog_x_axis = axis; |
| 252 | controller_number = port; | 266 | controller_number = static_cast<int>(port); |
| 253 | } else if (analog_y_axis == -1 && analog_x_axis != axis && controller_number == port) { | 267 | } else if (analog_y_axis == -1 && analog_x_axis != axis && controller_number == port) { |
| 254 | analog_y_axis = axis; | 268 | analog_y_axis = axis; |
| 255 | } | 269 | } |
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: | |||
| 25 | */ | 25 | */ |
| 26 | std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override; | 26 | std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override; |
| 27 | 27 | ||
| 28 | Common::ParamPackage GetNextInput(); | 28 | Common::ParamPackage GetNextInput() const; |
| 29 | 29 | ||
| 30 | /// For device input configuration/polling | 30 | /// For device input configuration/polling |
| 31 | void BeginConfiguration(); | 31 | 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 @@ | |||
| 4 | 4 | ||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | #include <thread> | 6 | #include <thread> |
| 7 | #include <libusb.h> | ||
| 8 | #include "common/param_package.h" | 7 | #include "common/param_package.h" |
| 9 | #include "input_common/analog_from_button.h" | 8 | #include "input_common/analog_from_button.h" |
| 10 | #include "input_common/gcadapter/gc_adapter.h" | 9 | #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( | |||
| 234 | std::function<void(Status)> status_callback, | 234 | std::function<void(Status)> status_callback, |
| 235 | std::function<void(u16, u16, u16, u16)> data_callback) { | 235 | std::function<void(u16, u16, u16, u16)> data_callback) { |
| 236 | 236 | ||
| 237 | std::thread([=] { | 237 | std::thread([=, this] { |
| 238 | constexpr u16 CALIBRATION_THRESHOLD = 100; | 238 | constexpr u16 CALIBRATION_THRESHOLD = 100; |
| 239 | 239 | ||
| 240 | u16 min_x{UINT16_MAX}; | 240 | 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 @@ | |||
| 14 | 14 | ||
| 15 | namespace Tegra::Engines { | 15 | namespace Tegra::Engines { |
| 16 | 16 | ||
| 17 | using namespace Texture; | ||
| 18 | |||
| 17 | MaxwellDMA::MaxwellDMA(Core::System& system, MemoryManager& memory_manager) | 19 | MaxwellDMA::MaxwellDMA(Core::System& system, MemoryManager& memory_manager) |
| 18 | : system{system}, memory_manager{memory_manager} {} | 20 | : system{system}, memory_manager{memory_manager} {} |
| 19 | 21 | ||
| 20 | void MaxwellDMA::CallMethod(u32 method, u32 method_argument, bool is_last_call) { | 22 | void MaxwellDMA::CallMethod(u32 method, u32 method_argument, bool is_last_call) { |
| 21 | ASSERT_MSG(method < Regs::NUM_REGS, | 23 | ASSERT_MSG(method < NUM_REGS, "Invalid MaxwellDMA register"); |
| 22 | "Invalid MaxwellDMA register, increase the size of the Regs structure"); | ||
| 23 | 24 | ||
| 24 | regs.reg_array[method] = method_argument; | 25 | regs.reg_array[method] = method_argument; |
| 25 | 26 | ||
| 26 | #define MAXWELLDMA_REG_INDEX(field_name) \ | 27 | if (method == offsetof(Regs, launch_dma) / sizeof(u32)) { |
| 27 | (offsetof(Tegra::Engines::MaxwellDMA::Regs, field_name) / sizeof(u32)) | 28 | Launch(); |
| 28 | |||
| 29 | switch (method) { | ||
| 30 | case MAXWELLDMA_REG_INDEX(exec): { | ||
| 31 | HandleCopy(); | ||
| 32 | break; | ||
| 33 | } | ||
| 34 | } | 29 | } |
| 35 | |||
| 36 | #undef MAXWELLDMA_REG_INDEX | ||
| 37 | } | 30 | } |
| 38 | 31 | ||
| 39 | void MaxwellDMA::CallMultiMethod(u32 method, const u32* base_start, u32 amount, | 32 | void MaxwellDMA::CallMultiMethod(u32 method, const u32* base_start, u32 amount, |
| 40 | u32 methods_pending) { | 33 | u32 methods_pending) { |
| 41 | for (std::size_t i = 0; i < amount; i++) { | 34 | for (size_t i = 0; i < amount; ++i) { |
| 42 | CallMethod(method, base_start[i], methods_pending - static_cast<u32>(i) <= 1); | 35 | CallMethod(method, base_start[i], methods_pending - static_cast<u32>(i) <= 1); |
| 43 | } | 36 | } |
| 44 | } | 37 | } |
| 45 | 38 | ||
| 46 | void MaxwellDMA::HandleCopy() { | 39 | void MaxwellDMA::Launch() { |
| 47 | LOG_TRACE(HW_GPU, "Requested a DMA copy"); | 40 | LOG_TRACE(Render_OpenGL, "DMA copy 0x{:x} -> 0x{:x}", static_cast<GPUVAddr>(regs.offset_in), |
| 48 | 41 | static_cast<GPUVAddr>(regs.offset_out)); | |
| 49 | const GPUVAddr source = regs.src_address.Address(); | ||
| 50 | const GPUVAddr dest = regs.dst_address.Address(); | ||
| 51 | 42 | ||
| 52 | // TODO(Subv): Perform more research and implement all features of this engine. | 43 | // TODO(Subv): Perform more research and implement all features of this engine. |
| 53 | ASSERT(regs.exec.enable_swizzle == 0); | 44 | const LaunchDMA& launch = regs.launch_dma; |
| 54 | ASSERT(regs.exec.query_mode == Regs::QueryMode::None); | 45 | ASSERT(launch.remap_enable == 0); |
| 55 | ASSERT(regs.exec.query_intr == Regs::QueryIntr::None); | 46 | ASSERT(launch.semaphore_type == LaunchDMA::SemaphoreType::NONE); |
| 56 | ASSERT(regs.exec.copy_mode == Regs::CopyMode::Unk2); | 47 | ASSERT(launch.interrupt_type == LaunchDMA::InterruptType::NONE); |
| 57 | ASSERT(regs.dst_params.pos_x == 0); | 48 | ASSERT(launch.data_transfer_type == LaunchDMA::DataTransferType::NON_PIPELINED); |
| 58 | ASSERT(regs.dst_params.pos_y == 0); | 49 | ASSERT(regs.dst_params.origin.x == 0); |
| 59 | 50 | ASSERT(regs.dst_params.origin.y == 0); | |
| 60 | if (!regs.exec.is_dst_linear && !regs.exec.is_src_linear) { | 51 | |
| 52 | const bool is_src_pitch = launch.src_memory_layout == LaunchDMA::MemoryLayout::PITCH; | ||
| 53 | const bool is_dst_pitch = launch.dst_memory_layout == LaunchDMA::MemoryLayout::PITCH; | ||
| 54 | |||
| 55 | if (!is_src_pitch && !is_dst_pitch) { | ||
| 61 | // If both the source and the destination are in block layout, assert. | 56 | // If both the source and the destination are in block layout, assert. |
| 62 | UNREACHABLE_MSG("Tiled->Tiled DMA transfers are not yet implemented"); | 57 | UNREACHABLE_MSG("Tiled->Tiled DMA transfers are not yet implemented"); |
| 63 | return; | 58 | return; |
| @@ -66,144 +61,161 @@ void MaxwellDMA::HandleCopy() { | |||
| 66 | // All copies here update the main memory, so mark all rasterizer states as invalid. | 61 | // All copies here update the main memory, so mark all rasterizer states as invalid. |
| 67 | system.GPU().Maxwell3D().OnMemoryWrite(); | 62 | system.GPU().Maxwell3D().OnMemoryWrite(); |
| 68 | 63 | ||
| 69 | if (regs.exec.is_dst_linear && regs.exec.is_src_linear) { | 64 | if (is_src_pitch && is_dst_pitch) { |
| 70 | // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D | 65 | CopyPitchToPitch(); |
| 71 | // buffer of length `x_count`, otherwise we copy a 2D image of dimensions (x_count, | 66 | } else { |
| 72 | // y_count). | 67 | ASSERT(launch.multi_line_enable == 1); |
| 73 | if (!regs.exec.enable_2d) { | ||
| 74 | memory_manager.CopyBlock(dest, source, regs.x_count); | ||
| 75 | return; | ||
| 76 | } | ||
| 77 | 68 | ||
| 78 | // If both the source and the destination are in linear layout, perform a line-by-line | 69 | if (!is_src_pitch && is_dst_pitch) { |
| 79 | // copy. We're going to take a subrect of size (x_count, y_count) from the source | 70 | CopyBlockLinearToPitch(); |
| 80 | // rectangle. There is no need to manually flush/invalidate the regions because | 71 | } else { |
| 81 | // CopyBlock does that for us. | 72 | CopyPitchToBlockLinear(); |
| 82 | for (u32 line = 0; line < regs.y_count; ++line) { | ||
| 83 | const GPUVAddr source_line = source + line * regs.src_pitch; | ||
| 84 | const GPUVAddr dest_line = dest + line * regs.dst_pitch; | ||
| 85 | memory_manager.CopyBlock(dest_line, source_line, regs.x_count); | ||
| 86 | } | 73 | } |
| 87 | return; | ||
| 88 | } | 74 | } |
| 75 | } | ||
| 89 | 76 | ||
| 90 | ASSERT(regs.exec.enable_2d == 1); | 77 | void MaxwellDMA::CopyPitchToPitch() { |
| 91 | 78 | // When `multi_line_enable` bit is disabled the copy is performed as if we were copying a 1D | |
| 92 | if (regs.exec.is_dst_linear && !regs.exec.is_src_linear) { | 79 | // buffer of length `line_length_in`. |
| 93 | 80 | // Otherwise we copy a 2D image of dimensions (line_length_in, line_count). | |
| 94 | ASSERT(regs.src_params.BlockDepth() == 0); | 81 | if (!regs.launch_dma.multi_line_enable) { |
| 95 | // Optimized path for micro copies. | 82 | memory_manager.CopyBlock(regs.offset_out, regs.offset_in, regs.line_length_in); |
| 96 | if (regs.dst_pitch * regs.y_count < Texture::GetGOBSize() && regs.dst_pitch <= 64) { | 83 | return; |
| 97 | const u32 bytes_per_pixel = regs.dst_pitch / regs.x_count; | 84 | } |
| 98 | const std::size_t src_size = Texture::GetGOBSize(); | ||
| 99 | const std::size_t dst_size = regs.dst_pitch * regs.y_count; | ||
| 100 | u32 pos_x = regs.src_params.pos_x; | ||
| 101 | u32 pos_y = regs.src_params.pos_y; | ||
| 102 | const u64 offset = | ||
| 103 | Texture::GetGOBOffset(regs.src_params.size_x, regs.src_params.size_y, pos_x, pos_y, | ||
| 104 | regs.src_params.BlockDepth(), bytes_per_pixel); | ||
| 105 | const u32 x_in_gob = 64 / bytes_per_pixel; | ||
| 106 | pos_x = pos_x % x_in_gob; | ||
| 107 | pos_y = pos_y % 8; | ||
| 108 | |||
| 109 | if (read_buffer.size() < src_size) { | ||
| 110 | read_buffer.resize(src_size); | ||
| 111 | } | ||
| 112 | |||
| 113 | if (write_buffer.size() < dst_size) { | ||
| 114 | write_buffer.resize(dst_size); | ||
| 115 | } | ||
| 116 | |||
| 117 | if (Settings::IsGPULevelExtreme()) { | ||
| 118 | memory_manager.ReadBlock(source + offset, read_buffer.data(), src_size); | ||
| 119 | memory_manager.ReadBlock(dest, write_buffer.data(), dst_size); | ||
| 120 | } else { | ||
| 121 | memory_manager.ReadBlockUnsafe(source + offset, read_buffer.data(), src_size); | ||
| 122 | memory_manager.ReadBlockUnsafe(dest, write_buffer.data(), dst_size); | ||
| 123 | } | ||
| 124 | |||
| 125 | Texture::UnswizzleSubrect(regs.x_count, regs.y_count, regs.dst_pitch, | ||
| 126 | regs.src_params.size_x, bytes_per_pixel, read_buffer.data(), | ||
| 127 | write_buffer.data(), regs.src_params.BlockHeight(), pos_x, | ||
| 128 | pos_y); | ||
| 129 | |||
| 130 | memory_manager.WriteBlock(dest, write_buffer.data(), dst_size); | ||
| 131 | |||
| 132 | return; | ||
| 133 | } | ||
| 134 | // If the input is tiled and the output is linear, deswizzle the input and copy it over. | ||
| 135 | const u32 bytes_per_pixel = regs.dst_pitch / regs.x_count; | ||
| 136 | const std::size_t src_size = Texture::CalculateSize( | ||
| 137 | true, bytes_per_pixel, regs.src_params.size_x, regs.src_params.size_y, | ||
| 138 | regs.src_params.size_z, regs.src_params.BlockHeight(), regs.src_params.BlockDepth()); | ||
| 139 | |||
| 140 | const std::size_t src_layer_size = Texture::CalculateSize( | ||
| 141 | true, bytes_per_pixel, regs.src_params.size_x, regs.src_params.size_y, 1, | ||
| 142 | regs.src_params.BlockHeight(), regs.src_params.BlockDepth()); | ||
| 143 | |||
| 144 | const std::size_t dst_size = regs.dst_pitch * regs.y_count; | ||
| 145 | 85 | ||
| 146 | if (read_buffer.size() < src_size) { | 86 | // Perform a line-by-line copy. |
| 147 | read_buffer.resize(src_size); | 87 | // We're going to take a subrect of size (line_length_in, line_count) from the source rectangle. |
| 148 | } | 88 | // There is no need to manually flush/invalidate the regions because CopyBlock does that for us. |
| 89 | for (u32 line = 0; line < regs.line_count; ++line) { | ||
| 90 | const GPUVAddr source_line = regs.offset_in + static_cast<size_t>(line) * regs.pitch_in; | ||
| 91 | const GPUVAddr dest_line = regs.offset_out + static_cast<size_t>(line) * regs.pitch_out; | ||
| 92 | memory_manager.CopyBlock(dest_line, source_line, regs.line_length_in); | ||
| 93 | } | ||
| 94 | } | ||
| 149 | 95 | ||
| 150 | if (write_buffer.size() < dst_size) { | 96 | void MaxwellDMA::CopyBlockLinearToPitch() { |
| 151 | write_buffer.resize(dst_size); | 97 | ASSERT(regs.src_params.block_size.depth == 0); |
| 152 | } | ||
| 153 | 98 | ||
| 154 | if (Settings::IsGPULevelExtreme()) { | 99 | // Optimized path for micro copies. |
| 155 | memory_manager.ReadBlock(source, read_buffer.data(), src_size); | 100 | const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count; |
| 156 | memory_manager.ReadBlock(dest, write_buffer.data(), dst_size); | 101 | if (dst_size < GOB_SIZE && regs.pitch_out <= GOB_SIZE_X) { |
| 157 | } else { | 102 | FastCopyBlockLinearToPitch(); |
| 158 | memory_manager.ReadBlockUnsafe(source, read_buffer.data(), src_size); | 103 | return; |
| 159 | memory_manager.ReadBlockUnsafe(dest, write_buffer.data(), dst_size); | 104 | } |
| 160 | } | ||
| 161 | 105 | ||
| 162 | Texture::UnswizzleSubrect( | 106 | // Deswizzle the input and copy it over. |
| 163 | regs.x_count, regs.y_count, regs.dst_pitch, regs.src_params.size_x, bytes_per_pixel, | 107 | const u32 bytes_per_pixel = regs.pitch_out / regs.line_length_in; |
| 164 | read_buffer.data() + src_layer_size * regs.src_params.pos_z, write_buffer.data(), | 108 | const Parameters& src_params = regs.src_params; |
| 165 | regs.src_params.BlockHeight(), regs.src_params.pos_x, regs.src_params.pos_y); | 109 | const u32 width = src_params.width; |
| 110 | const u32 height = src_params.height; | ||
| 111 | const u32 depth = src_params.depth; | ||
| 112 | const u32 block_height = src_params.block_size.height; | ||
| 113 | const u32 block_depth = src_params.block_size.depth; | ||
| 114 | const size_t src_size = | ||
| 115 | CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth); | ||
| 116 | const size_t src_layer_size = | ||
| 117 | CalculateSize(true, bytes_per_pixel, width, height, 1, block_height, block_depth); | ||
| 118 | |||
| 119 | if (read_buffer.size() < src_size) { | ||
| 120 | read_buffer.resize(src_size); | ||
| 121 | } | ||
| 122 | if (write_buffer.size() < dst_size) { | ||
| 123 | write_buffer.resize(dst_size); | ||
| 124 | } | ||
| 166 | 125 | ||
| 167 | memory_manager.WriteBlock(dest, write_buffer.data(), dst_size); | 126 | if (Settings::IsGPULevelExtreme()) { |
| 127 | memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size); | ||
| 128 | memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size); | ||
| 168 | } else { | 129 | } else { |
| 169 | ASSERT(regs.dst_params.BlockDepth() == 0); | 130 | memory_manager.ReadBlockUnsafe(regs.offset_in, read_buffer.data(), src_size); |
| 131 | memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size); | ||
| 132 | } | ||
| 170 | 133 | ||
| 171 | const u32 bytes_per_pixel = regs.src_pitch / regs.x_count; | 134 | UnswizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_out, width, bytes_per_pixel, |
| 135 | read_buffer.data() + src_layer_size * src_params.layer, write_buffer.data(), | ||
| 136 | block_height, src_params.origin.x, src_params.origin.y); | ||
| 172 | 137 | ||
| 173 | const std::size_t dst_size = Texture::CalculateSize( | 138 | memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size); |
| 174 | true, bytes_per_pixel, regs.dst_params.size_x, regs.dst_params.size_y, | 139 | } |
| 175 | regs.dst_params.size_z, regs.dst_params.BlockHeight(), regs.dst_params.BlockDepth()); | ||
| 176 | 140 | ||
| 177 | const std::size_t dst_layer_size = Texture::CalculateSize( | 141 | void MaxwellDMA::CopyPitchToBlockLinear() { |
| 178 | true, bytes_per_pixel, regs.dst_params.size_x, regs.dst_params.size_y, 1, | 142 | const auto& dst_params = regs.dst_params; |
| 179 | regs.dst_params.BlockHeight(), regs.dst_params.BlockDepth()); | 143 | const u32 bytes_per_pixel = regs.pitch_in / regs.line_length_in; |
| 144 | const u32 width = dst_params.width; | ||
| 145 | const u32 height = dst_params.height; | ||
| 146 | const u32 depth = dst_params.depth; | ||
| 147 | const u32 block_height = dst_params.block_size.height; | ||
| 148 | const u32 block_depth = dst_params.block_size.depth; | ||
| 149 | const size_t dst_size = | ||
| 150 | CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth); | ||
| 151 | const size_t dst_layer_size = | ||
| 152 | CalculateSize(true, bytes_per_pixel, width, height, 1, block_height, block_depth); | ||
| 153 | |||
| 154 | const size_t src_size = static_cast<size_t>(regs.pitch_in) * regs.line_count; | ||
| 155 | |||
| 156 | if (read_buffer.size() < src_size) { | ||
| 157 | read_buffer.resize(src_size); | ||
| 158 | } | ||
| 159 | if (write_buffer.size() < dst_size) { | ||
| 160 | write_buffer.resize(dst_size); | ||
| 161 | } | ||
| 180 | 162 | ||
| 181 | const std::size_t src_size = regs.src_pitch * regs.y_count; | 163 | if (Settings::IsGPULevelExtreme()) { |
| 164 | memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size); | ||
| 165 | memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size); | ||
| 166 | } else { | ||
| 167 | memory_manager.ReadBlockUnsafe(regs.offset_in, read_buffer.data(), src_size); | ||
| 168 | memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size); | ||
| 169 | } | ||
| 182 | 170 | ||
| 183 | if (read_buffer.size() < src_size) { | 171 | // If the input is linear and the output is tiled, swizzle the input and copy it over. |
| 184 | read_buffer.resize(src_size); | 172 | if (regs.dst_params.block_size.depth > 0) { |
| 185 | } | 173 | ASSERT(dst_params.layer == 0); |
| 174 | SwizzleSliceToVoxel(regs.line_length_in, regs.line_count, regs.pitch_in, width, height, | ||
| 175 | bytes_per_pixel, block_height, block_depth, dst_params.origin.x, | ||
| 176 | dst_params.origin.y, write_buffer.data(), read_buffer.data()); | ||
| 177 | } else { | ||
| 178 | SwizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_in, width, bytes_per_pixel, | ||
| 179 | write_buffer.data() + dst_layer_size * dst_params.layer, read_buffer.data(), | ||
| 180 | block_height, dst_params.origin.x, dst_params.origin.y); | ||
| 181 | } | ||
| 186 | 182 | ||
| 187 | if (write_buffer.size() < dst_size) { | 183 | memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size); |
| 188 | write_buffer.resize(dst_size); | 184 | } |
| 189 | } | ||
| 190 | 185 | ||
| 191 | if (Settings::IsGPULevelExtreme()) { | 186 | void MaxwellDMA::FastCopyBlockLinearToPitch() { |
| 192 | memory_manager.ReadBlock(source, read_buffer.data(), src_size); | 187 | const u32 bytes_per_pixel = regs.pitch_out / regs.line_length_in; |
| 193 | memory_manager.ReadBlock(dest, write_buffer.data(), dst_size); | 188 | const size_t src_size = GOB_SIZE; |
| 194 | } else { | 189 | const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count; |
| 195 | memory_manager.ReadBlockUnsafe(source, read_buffer.data(), src_size); | 190 | u32 pos_x = regs.src_params.origin.x; |
| 196 | memory_manager.ReadBlockUnsafe(dest, write_buffer.data(), dst_size); | 191 | u32 pos_y = regs.src_params.origin.y; |
| 197 | } | 192 | const u64 offset = GetGOBOffset(regs.src_params.width, regs.src_params.height, pos_x, pos_y, |
| 193 | regs.src_params.block_size.height, bytes_per_pixel); | ||
| 194 | const u32 x_in_gob = 64 / bytes_per_pixel; | ||
| 195 | pos_x = pos_x % x_in_gob; | ||
| 196 | pos_y = pos_y % 8; | ||
| 197 | |||
| 198 | if (read_buffer.size() < src_size) { | ||
| 199 | read_buffer.resize(src_size); | ||
| 200 | } | ||
| 198 | 201 | ||
| 199 | // If the input is linear and the output is tiled, swizzle the input and copy it over. | 202 | if (write_buffer.size() < dst_size) { |
| 200 | Texture::SwizzleSubrect( | 203 | write_buffer.resize(dst_size); |
| 201 | regs.x_count, regs.y_count, regs.src_pitch, regs.dst_params.size_x, bytes_per_pixel, | 204 | } |
| 202 | write_buffer.data() + dst_layer_size * regs.dst_params.pos_z, read_buffer.data(), | ||
| 203 | regs.dst_params.BlockHeight(), regs.dst_params.pos_x, regs.dst_params.pos_y); | ||
| 204 | 205 | ||
| 205 | memory_manager.WriteBlock(dest, write_buffer.data(), dst_size); | 206 | if (Settings::IsGPULevelExtreme()) { |
| 207 | memory_manager.ReadBlock(regs.offset_in + offset, read_buffer.data(), src_size); | ||
| 208 | memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size); | ||
| 209 | } else { | ||
| 210 | memory_manager.ReadBlockUnsafe(regs.offset_in + offset, read_buffer.data(), src_size); | ||
| 211 | memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size); | ||
| 206 | } | 212 | } |
| 213 | |||
| 214 | UnswizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_out, regs.src_params.width, | ||
| 215 | bytes_per_pixel, read_buffer.data(), write_buffer.data(), | ||
| 216 | regs.src_params.block_size.height, pos_x, pos_y); | ||
| 217 | |||
| 218 | memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size); | ||
| 207 | } | 219 | } |
| 208 | 220 | ||
| 209 | } // namespace Tegra::Engines | 221 | } // 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; | |||
| 24 | namespace Tegra::Engines { | 24 | namespace Tegra::Engines { |
| 25 | 25 | ||
| 26 | /** | 26 | /** |
| 27 | * This Engine is known as GK104_Copy. Documentation can be found in: | 27 | * This engine is known as gk104_copy. Documentation can be found in: |
| 28 | * https://github.com/NVIDIA/open-gpu-doc/blob/master/classes/dma-copy/clb0b5.h | ||
| 28 | * https://github.com/envytools/envytools/blob/master/rnndb/fifo/gk104_copy.xml | 29 | * https://github.com/envytools/envytools/blob/master/rnndb/fifo/gk104_copy.xml |
| 29 | */ | 30 | */ |
| 30 | 31 | ||
| 31 | class MaxwellDMA final : public EngineInterface { | 32 | class MaxwellDMA final : public EngineInterface { |
| 32 | public: | 33 | public: |
| 33 | explicit MaxwellDMA(Core::System& system, MemoryManager& memory_manager); | 34 | struct PackedGPUVAddr { |
| 34 | ~MaxwellDMA() = default; | 35 | u32 upper; |
| 35 | 36 | u32 lower; | |
| 36 | /// Write the value to the register identified by method. | 37 | |
| 37 | void CallMethod(u32 method, u32 method_argument, bool is_last_call) override; | 38 | constexpr operator GPUVAddr() const noexcept { |
| 38 | 39 | return (static_cast<GPUVAddr>(upper & 0xff) << 32) | lower; | |
| 39 | /// Write multiple values to the register identified by method. | 40 | } |
| 40 | void CallMultiMethod(u32 method, const u32* base_start, u32 amount, | 41 | }; |
| 41 | u32 methods_pending) override; | 42 | |
| 43 | union BlockSize { | ||
| 44 | BitField<0, 4, u32> width; | ||
| 45 | BitField<4, 4, u32> height; | ||
| 46 | BitField<8, 4, u32> depth; | ||
| 47 | BitField<12, 4, u32> gob_height; | ||
| 48 | }; | ||
| 49 | static_assert(sizeof(BlockSize) == 4); | ||
| 50 | |||
| 51 | union Origin { | ||
| 52 | BitField<0, 16, u32> x; | ||
| 53 | BitField<16, 16, u32> y; | ||
| 54 | }; | ||
| 55 | static_assert(sizeof(Origin) == 4); | ||
| 56 | |||
| 57 | struct Parameters { | ||
| 58 | BlockSize block_size; | ||
| 59 | u32 width; | ||
| 60 | u32 height; | ||
| 61 | u32 depth; | ||
| 62 | u32 layer; | ||
| 63 | Origin origin; | ||
| 64 | }; | ||
| 65 | static_assert(sizeof(Parameters) == 24); | ||
| 66 | |||
| 67 | struct Semaphore { | ||
| 68 | PackedGPUVAddr address; | ||
| 69 | u32 payload; | ||
| 70 | }; | ||
| 71 | static_assert(sizeof(Semaphore) == 12); | ||
| 72 | |||
| 73 | struct RenderEnable { | ||
| 74 | enum class Mode : u32 { | ||
| 75 | FALSE = 0, | ||
| 76 | TRUE = 1, | ||
| 77 | CONDITIONAL = 2, | ||
| 78 | RENDER_IF_EQUAL = 3, | ||
| 79 | RENDER_IF_NOT_EQUAL = 4, | ||
| 80 | }; | ||
| 42 | 81 | ||
| 43 | struct Regs { | 82 | PackedGPUVAddr address; |
| 44 | static constexpr std::size_t NUM_REGS = 0x1D6; | 83 | BitField<0, 3, Mode> mode; |
| 84 | }; | ||
| 85 | static_assert(sizeof(RenderEnable) == 12); | ||
| 86 | |||
| 87 | enum class PhysModeTarget : u32 { | ||
| 88 | LOCAL_FB = 0, | ||
| 89 | COHERENT_SYSMEM = 1, | ||
| 90 | NONCOHERENT_SYSMEM = 2, | ||
| 91 | }; | ||
| 92 | using PhysMode = BitField<0, 2, PhysModeTarget>; | ||
| 93 | |||
| 94 | union LaunchDMA { | ||
| 95 | enum class DataTransferType : u32 { | ||
| 96 | NONE = 0, | ||
| 97 | PIPELINED = 1, | ||
| 98 | NON_PIPELINED = 2, | ||
| 99 | }; | ||
| 45 | 100 | ||
| 46 | struct Parameters { | 101 | enum class SemaphoreType : u32 { |
| 47 | union { | 102 | NONE = 0, |
| 48 | BitField<0, 4, u32> block_depth; | 103 | RELEASE_ONE_WORD_SEMAPHORE = 1, |
| 49 | BitField<4, 4, u32> block_height; | 104 | RELEASE_FOUR_WORD_SEMAPHORE = 2, |
| 50 | BitField<8, 4, u32> block_width; | 105 | }; |
| 51 | }; | ||
| 52 | u32 size_x; | ||
| 53 | u32 size_y; | ||
| 54 | u32 size_z; | ||
| 55 | u32 pos_z; | ||
| 56 | union { | ||
| 57 | BitField<0, 16, u32> pos_x; | ||
| 58 | BitField<16, 16, u32> pos_y; | ||
| 59 | }; | ||
| 60 | 106 | ||
| 61 | u32 BlockHeight() const { | 107 | enum class InterruptType : u32 { |
| 62 | return block_height.Value(); | 108 | NONE = 0, |
| 63 | } | 109 | BLOCKING = 1, |
| 110 | NON_BLOCKING = 2, | ||
| 111 | }; | ||
| 64 | 112 | ||
| 65 | u32 BlockDepth() const { | 113 | enum class MemoryLayout : u32 { |
| 66 | return block_depth.Value(); | 114 | BLOCKLINEAR = 0, |
| 67 | } | 115 | PITCH = 1, |
| 68 | }; | 116 | }; |
| 69 | 117 | ||
| 70 | static_assert(sizeof(Parameters) == 24, "Parameters has wrong size"); | 118 | enum class Type : u32 { |
| 119 | VIRTUAL = 0, | ||
| 120 | PHYSICAL = 1, | ||
| 121 | }; | ||
| 71 | 122 | ||
| 72 | enum class ComponentMode : u32 { | 123 | enum class SemaphoreReduction : u32 { |
| 73 | Src0 = 0, | 124 | IMIN = 0, |
| 74 | Src1 = 1, | 125 | IMAX = 1, |
| 75 | Src2 = 2, | 126 | IXOR = 2, |
| 76 | Src3 = 3, | 127 | IAND = 3, |
| 77 | Const0 = 4, | 128 | IOR = 4, |
| 78 | Const1 = 5, | 129 | IADD = 5, |
| 79 | Zero = 6, | 130 | INC = 6, |
| 131 | DEC = 7, | ||
| 132 | FADD = 0xA, | ||
| 80 | }; | 133 | }; |
| 81 | 134 | ||
| 82 | enum class CopyMode : u32 { | 135 | enum class SemaphoreReductionSign : u32 { |
| 83 | None = 0, | 136 | SIGNED = 0, |
| 84 | Unk1 = 1, | 137 | UNSIGNED = 1, |
| 85 | Unk2 = 2, | ||
| 86 | }; | 138 | }; |
| 87 | 139 | ||
| 88 | enum class QueryMode : u32 { | 140 | enum class BypassL2 : u32 { |
| 89 | None = 0, | 141 | USE_PTE_SETTING = 0, |
| 90 | Short = 1, | 142 | FORCE_VOLATILE = 1, |
| 91 | Long = 2, | ||
| 92 | }; | 143 | }; |
| 93 | 144 | ||
| 94 | enum class QueryIntr : u32 { | 145 | BitField<0, 2, DataTransferType> data_transfer_type; |
| 95 | None = 0, | 146 | BitField<2, 1, u32> flush_enable; |
| 96 | Block = 1, | 147 | BitField<3, 2, SemaphoreType> semaphore_type; |
| 97 | NonBlock = 2, | 148 | BitField<5, 2, InterruptType> interrupt_type; |
| 149 | BitField<7, 1, MemoryLayout> src_memory_layout; | ||
| 150 | BitField<8, 1, MemoryLayout> dst_memory_layout; | ||
| 151 | BitField<9, 1, u32> multi_line_enable; | ||
| 152 | BitField<10, 1, u32> remap_enable; | ||
| 153 | BitField<11, 1, u32> rmwdisable; | ||
| 154 | BitField<12, 1, Type> src_type; | ||
| 155 | BitField<13, 1, Type> dst_type; | ||
| 156 | BitField<14, 4, SemaphoreReduction> semaphore_reduction; | ||
| 157 | BitField<18, 1, SemaphoreReductionSign> semaphore_reduction_sign; | ||
| 158 | BitField<19, 1, u32> reduction_enable; | ||
| 159 | BitField<20, 1, BypassL2> bypass_l2; | ||
| 160 | }; | ||
| 161 | static_assert(sizeof(LaunchDMA) == 4); | ||
| 162 | |||
| 163 | struct RemapConst { | ||
| 164 | enum Swizzle : u32 { | ||
| 165 | SRC_X = 0, | ||
| 166 | SRC_Y = 1, | ||
| 167 | SRC_Z = 2, | ||
| 168 | SRC_W = 3, | ||
| 169 | CONST_A = 4, | ||
| 170 | CONST_B = 5, | ||
| 171 | NO_WRITE = 6, | ||
| 98 | }; | 172 | }; |
| 99 | 173 | ||
| 100 | union { | 174 | PackedGPUVAddr address; |
| 101 | struct { | ||
| 102 | INSERT_UNION_PADDING_WORDS(0xC0); | ||
| 103 | |||
| 104 | struct { | ||
| 105 | union { | ||
| 106 | BitField<0, 2, CopyMode> copy_mode; | ||
| 107 | BitField<2, 1, u32> flush; | ||
| 108 | |||
| 109 | BitField<3, 2, QueryMode> query_mode; | ||
| 110 | BitField<5, 2, QueryIntr> query_intr; | ||
| 111 | |||
| 112 | BitField<7, 1, u32> is_src_linear; | ||
| 113 | BitField<8, 1, u32> is_dst_linear; | ||
| 114 | |||
| 115 | BitField<9, 1, u32> enable_2d; | ||
| 116 | BitField<10, 1, u32> enable_swizzle; | ||
| 117 | }; | ||
| 118 | } exec; | ||
| 119 | |||
| 120 | INSERT_UNION_PADDING_WORDS(0x3F); | ||
| 121 | |||
| 122 | struct { | ||
| 123 | u32 address_high; | ||
| 124 | u32 address_low; | ||
| 125 | |||
| 126 | GPUVAddr Address() const { | ||
| 127 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | | ||
| 128 | address_low); | ||
| 129 | } | ||
| 130 | } src_address; | ||
| 131 | |||
| 132 | struct { | ||
| 133 | u32 address_high; | ||
| 134 | u32 address_low; | ||
| 135 | |||
| 136 | GPUVAddr Address() const { | ||
| 137 | return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | | ||
| 138 | address_low); | ||
| 139 | } | ||
| 140 | } dst_address; | ||
| 141 | |||
| 142 | u32 src_pitch; | ||
| 143 | u32 dst_pitch; | ||
| 144 | u32 x_count; | ||
| 145 | u32 y_count; | ||
| 146 | |||
| 147 | INSERT_UNION_PADDING_WORDS(0xB8); | ||
| 148 | |||
| 149 | u32 const0; | ||
| 150 | u32 const1; | ||
| 151 | union { | ||
| 152 | BitField<0, 4, ComponentMode> component0; | ||
| 153 | BitField<4, 4, ComponentMode> component1; | ||
| 154 | BitField<8, 4, ComponentMode> component2; | ||
| 155 | BitField<12, 4, ComponentMode> component3; | ||
| 156 | BitField<16, 2, u32> component_size; | ||
| 157 | BitField<20, 3, u32> src_num_components; | ||
| 158 | BitField<24, 3, u32> dst_num_components; | ||
| 159 | |||
| 160 | u32 SrcBytePerPixel() const { | ||
| 161 | return src_num_components.Value() * component_size.Value(); | ||
| 162 | } | ||
| 163 | u32 DstBytePerPixel() const { | ||
| 164 | return dst_num_components.Value() * component_size.Value(); | ||
| 165 | } | ||
| 166 | } swizzle_config; | ||
| 167 | 175 | ||
| 168 | Parameters dst_params; | 176 | union { |
| 177 | BitField<0, 3, Swizzle> dst_x; | ||
| 178 | BitField<4, 3, Swizzle> dst_y; | ||
| 179 | BitField<8, 3, Swizzle> dst_z; | ||
| 180 | BitField<12, 3, Swizzle> dst_w; | ||
| 181 | BitField<16, 2, u32> component_size_minus_one; | ||
| 182 | BitField<20, 2, u32> num_src_components_minus_one; | ||
| 183 | BitField<24, 2, u32> num_dst_components_minus_one; | ||
| 184 | }; | ||
| 185 | }; | ||
| 186 | static_assert(sizeof(RemapConst) == 12); | ||
| 169 | 187 | ||
| 170 | INSERT_UNION_PADDING_WORDS(1); | 188 | explicit MaxwellDMA(Core::System& system, MemoryManager& memory_manager); |
| 189 | ~MaxwellDMA() = default; | ||
| 171 | 190 | ||
| 172 | Parameters src_params; | 191 | /// Write the value to the register identified by method. |
| 192 | void CallMethod(u32 method, u32 method_argument, bool is_last_call) override; | ||
| 173 | 193 | ||
| 174 | INSERT_UNION_PADDING_WORDS(0x13); | 194 | /// Write multiple values to the register identified by method. |
| 175 | }; | 195 | void CallMultiMethod(u32 method, const u32* base_start, u32 amount, |
| 176 | std::array<u32, NUM_REGS> reg_array; | 196 | u32 methods_pending) override; |
| 177 | }; | ||
| 178 | } regs{}; | ||
| 179 | 197 | ||
| 180 | private: | 198 | private: |
| 199 | /// Performs the copy from the source buffer to the destination buffer as configured in the | ||
| 200 | /// registers. | ||
| 201 | void Launch(); | ||
| 202 | |||
| 203 | void CopyPitchToPitch(); | ||
| 204 | |||
| 205 | void CopyBlockLinearToPitch(); | ||
| 206 | |||
| 207 | void CopyPitchToBlockLinear(); | ||
| 208 | |||
| 209 | void FastCopyBlockLinearToPitch(); | ||
| 210 | |||
| 181 | Core::System& system; | 211 | Core::System& system; |
| 182 | 212 | ||
| 183 | MemoryManager& memory_manager; | 213 | MemoryManager& memory_manager; |
| @@ -185,28 +215,58 @@ private: | |||
| 185 | std::vector<u8> read_buffer; | 215 | std::vector<u8> read_buffer; |
| 186 | std::vector<u8> write_buffer; | 216 | std::vector<u8> write_buffer; |
| 187 | 217 | ||
| 188 | /// Performs the copy from the source buffer to the destination buffer as configured in the | 218 | static constexpr std::size_t NUM_REGS = 0x800; |
| 189 | /// registers. | 219 | struct Regs { |
| 190 | void HandleCopy(); | 220 | union { |
| 191 | }; | 221 | struct { |
| 222 | u32 reserved[0x40]; | ||
| 223 | u32 nop; | ||
| 224 | u32 reserved01[0xf]; | ||
| 225 | u32 pm_trigger; | ||
| 226 | u32 reserved02[0x3f]; | ||
| 227 | Semaphore semaphore; | ||
| 228 | u32 reserved03[0x2]; | ||
| 229 | RenderEnable render_enable; | ||
| 230 | PhysMode src_phys_mode; | ||
| 231 | PhysMode dst_phys_mode; | ||
| 232 | u32 reserved04[0x26]; | ||
| 233 | LaunchDMA launch_dma; | ||
| 234 | u32 reserved05[0x3f]; | ||
| 235 | PackedGPUVAddr offset_in; | ||
| 236 | PackedGPUVAddr offset_out; | ||
| 237 | u32 pitch_in; | ||
| 238 | u32 pitch_out; | ||
| 239 | u32 line_length_in; | ||
| 240 | u32 line_count; | ||
| 241 | u32 reserved06[0xb8]; | ||
| 242 | RemapConst remap_const; | ||
| 243 | Parameters dst_params; | ||
| 244 | u32 reserved07[0x1]; | ||
| 245 | Parameters src_params; | ||
| 246 | u32 reserved08[0x275]; | ||
| 247 | u32 pm_trigger_end; | ||
| 248 | u32 reserved09[0x3ba]; | ||
| 249 | }; | ||
| 250 | std::array<u32, NUM_REGS> reg_array; | ||
| 251 | }; | ||
| 252 | } regs{}; | ||
| 192 | 253 | ||
| 193 | #define ASSERT_REG_POSITION(field_name, position) \ | 254 | #define ASSERT_REG_POSITION(field_name, position) \ |
| 194 | static_assert(offsetof(MaxwellDMA::Regs, field_name) == position * 4, \ | 255 | static_assert(offsetof(MaxwellDMA::Regs, field_name) == position * 4, \ |
| 195 | "Field " #field_name " has invalid position") | 256 | "Field " #field_name " has invalid position") |
| 196 | 257 | ||
| 197 | ASSERT_REG_POSITION(exec, 0xC0); | 258 | ASSERT_REG_POSITION(launch_dma, 0xC0); |
| 198 | ASSERT_REG_POSITION(src_address, 0x100); | 259 | ASSERT_REG_POSITION(offset_in, 0x100); |
| 199 | ASSERT_REG_POSITION(dst_address, 0x102); | 260 | ASSERT_REG_POSITION(offset_out, 0x102); |
| 200 | ASSERT_REG_POSITION(src_pitch, 0x104); | 261 | ASSERT_REG_POSITION(pitch_in, 0x104); |
| 201 | ASSERT_REG_POSITION(dst_pitch, 0x105); | 262 | ASSERT_REG_POSITION(pitch_out, 0x105); |
| 202 | ASSERT_REG_POSITION(x_count, 0x106); | 263 | ASSERT_REG_POSITION(line_length_in, 0x106); |
| 203 | ASSERT_REG_POSITION(y_count, 0x107); | 264 | ASSERT_REG_POSITION(line_count, 0x107); |
| 204 | ASSERT_REG_POSITION(const0, 0x1C0); | 265 | ASSERT_REG_POSITION(remap_const, 0x1C0); |
| 205 | ASSERT_REG_POSITION(const1, 0x1C1); | 266 | ASSERT_REG_POSITION(dst_params, 0x1C3); |
| 206 | ASSERT_REG_POSITION(swizzle_config, 0x1C2); | 267 | ASSERT_REG_POSITION(src_params, 0x1CA); |
| 207 | ASSERT_REG_POSITION(dst_params, 0x1C3); | ||
| 208 | ASSERT_REG_POSITION(src_params, 0x1CA); | ||
| 209 | 268 | ||
| 210 | #undef ASSERT_REG_POSITION | 269 | #undef ASSERT_REG_POSITION |
| 270 | }; | ||
| 211 | 271 | ||
| 212 | } // namespace Tegra::Engines | 272 | } // 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 { | |||
| 141 | std::array<f32, 2> tex_coord; | 141 | std::array<f32, 2> tex_coord; |
| 142 | 142 | ||
| 143 | static VkVertexInputBindingDescription GetDescription() { | 143 | static VkVertexInputBindingDescription GetDescription() { |
| 144 | VkVertexInputBindingDescription description; | 144 | return { |
| 145 | description.binding = 0; | 145 | .binding = 0, |
| 146 | description.stride = sizeof(ScreenRectVertex); | 146 | .stride = sizeof(ScreenRectVertex), |
| 147 | description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; | 147 | .inputRate = VK_VERTEX_INPUT_RATE_VERTEX, |
| 148 | return description; | 148 | }; |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | static std::array<VkVertexInputAttributeDescription, 2> GetAttributes() { | 151 | static std::array<VkVertexInputAttributeDescription, 2> GetAttributes() { |
| 152 | std::array<VkVertexInputAttributeDescription, 2> attributes; | 152 | return {{ |
| 153 | attributes[0].location = 0; | 153 | { |
| 154 | attributes[0].binding = 0; | 154 | .location = 0, |
| 155 | attributes[0].format = VK_FORMAT_R32G32_SFLOAT; | 155 | .binding = 0, |
| 156 | attributes[0].offset = offsetof(ScreenRectVertex, position); | 156 | .format = VK_FORMAT_R32G32_SFLOAT, |
| 157 | attributes[1].location = 1; | 157 | .offset = offsetof(ScreenRectVertex, position), |
| 158 | attributes[1].binding = 0; | 158 | }, |
| 159 | attributes[1].format = VK_FORMAT_R32G32_SFLOAT; | 159 | { |
| 160 | attributes[1].offset = offsetof(ScreenRectVertex, tex_coord); | 160 | .location = 1, |
| 161 | return attributes; | 161 | .binding = 0, |
| 162 | .format = VK_FORMAT_R32G32_SFLOAT, | ||
| 163 | .offset = offsetof(ScreenRectVertex, tex_coord), | ||
| 164 | }, | ||
| 165 | }}; | ||
| 162 | } | 166 | } |
| 163 | }; | 167 | }; |
| 164 | 168 | ||
| @@ -267,20 +271,25 @@ std::tuple<VKFence&, VkSemaphore> VKBlitScreen::Draw(const Tegra::FramebufferCon | |||
| 267 | blit_image->Transition(0, 1, 0, 1, VK_PIPELINE_STAGE_TRANSFER_BIT, | 271 | blit_image->Transition(0, 1, 0, 1, VK_PIPELINE_STAGE_TRANSFER_BIT, |
| 268 | VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); | 272 | VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); |
| 269 | 273 | ||
| 270 | VkBufferImageCopy copy; | 274 | const VkBufferImageCopy copy{ |
| 271 | copy.bufferOffset = image_offset; | 275 | .bufferOffset = image_offset, |
| 272 | copy.bufferRowLength = 0; | 276 | .bufferRowLength = 0, |
| 273 | copy.bufferImageHeight = 0; | 277 | .bufferImageHeight = 0, |
| 274 | copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; | 278 | .imageSubresource = |
| 275 | copy.imageSubresource.mipLevel = 0; | 279 | { |
| 276 | copy.imageSubresource.baseArrayLayer = 0; | 280 | .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, |
| 277 | copy.imageSubresource.layerCount = 1; | 281 | .mipLevel = 0, |
| 278 | copy.imageOffset.x = 0; | 282 | .baseArrayLayer = 0, |
| 279 | copy.imageOffset.y = 0; | 283 | .layerCount = 1, |
| 280 | copy.imageOffset.z = 0; | 284 | }, |
| 281 | copy.imageExtent.width = framebuffer.width; | 285 | .imageOffset = {.x = 0, .y = 0, .z = 0}, |
| 282 | copy.imageExtent.height = framebuffer.height; | 286 | .imageExtent = |
| 283 | copy.imageExtent.depth = 1; | 287 | { |
| 288 | .width = framebuffer.width, | ||
| 289 | .height = framebuffer.height, | ||
| 290 | .depth = 1, | ||
| 291 | }, | ||
| 292 | }; | ||
| 284 | scheduler.Record( | 293 | scheduler.Record( |
| 285 | [buffer = *buffer, image = *blit_image->GetHandle(), copy](vk::CommandBuffer cmdbuf) { | 294 | [buffer = *buffer, image = *blit_image->GetHandle(), copy](vk::CommandBuffer cmdbuf) { |
| 286 | cmdbuf.CopyBufferToImage(buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy); | 295 | cmdbuf.CopyBufferToImage(buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, copy); |
| @@ -295,11 +304,9 @@ std::tuple<VKFence&, VkSemaphore> VKBlitScreen::Draw(const Tegra::FramebufferCon | |||
| 295 | descriptor_set = descriptor_sets[image_index], buffer = *buffer, | 304 | descriptor_set = descriptor_sets[image_index], buffer = *buffer, |
| 296 | size = swapchain.GetSize(), pipeline = *pipeline, | 305 | size = swapchain.GetSize(), pipeline = *pipeline, |
| 297 | layout = *pipeline_layout](vk::CommandBuffer cmdbuf) { | 306 | layout = *pipeline_layout](vk::CommandBuffer cmdbuf) { |
| 298 | VkClearValue clear_color; | 307 | const VkClearValue clear_color{ |
| 299 | clear_color.color.float32[0] = 0.0f; | 308 | .color = {.float32 = {0.0f, 0.0f, 0.0f, 0.0f}}, |
| 300 | clear_color.color.float32[1] = 0.0f; | 309 | }; |
| 301 | clear_color.color.float32[2] = 0.0f; | ||
| 302 | clear_color.color.float32[3] = 0.0f; | ||
| 303 | 310 | ||
| 304 | VkRenderPassBeginInfo renderpass_bi; | 311 | VkRenderPassBeginInfo renderpass_bi; |
| 305 | renderpass_bi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; | 312 | renderpass_bi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; |
| @@ -379,93 +386,109 @@ void VKBlitScreen::CreateSemaphores() { | |||
| 379 | } | 386 | } |
| 380 | 387 | ||
| 381 | void VKBlitScreen::CreateDescriptorPool() { | 388 | void VKBlitScreen::CreateDescriptorPool() { |
| 382 | std::array<VkDescriptorPoolSize, 2> pool_sizes; | 389 | const std::array<VkDescriptorPoolSize, 2> pool_sizes{{ |
| 383 | pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; | 390 | { |
| 384 | pool_sizes[0].descriptorCount = static_cast<u32>(image_count); | 391 | .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, |
| 385 | pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; | 392 | .descriptorCount = static_cast<u32>(image_count), |
| 386 | pool_sizes[1].descriptorCount = static_cast<u32>(image_count); | 393 | }, |
| 387 | 394 | { | |
| 388 | VkDescriptorPoolCreateInfo ci; | 395 | .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| 389 | ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; | 396 | .descriptorCount = static_cast<u32>(image_count), |
| 390 | ci.pNext = nullptr; | 397 | }, |
| 391 | ci.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; | 398 | }}; |
| 392 | ci.maxSets = static_cast<u32>(image_count); | 399 | |
| 393 | ci.poolSizeCount = static_cast<u32>(pool_sizes.size()); | 400 | const VkDescriptorPoolCreateInfo ci{ |
| 394 | ci.pPoolSizes = pool_sizes.data(); | 401 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, |
| 402 | .pNext = nullptr, | ||
| 403 | .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, | ||
| 404 | .maxSets = static_cast<u32>(image_count), | ||
| 405 | .poolSizeCount = static_cast<u32>(pool_sizes.size()), | ||
| 406 | .pPoolSizes = pool_sizes.data(), | ||
| 407 | }; | ||
| 395 | descriptor_pool = device.GetLogical().CreateDescriptorPool(ci); | 408 | descriptor_pool = device.GetLogical().CreateDescriptorPool(ci); |
| 396 | } | 409 | } |
| 397 | 410 | ||
| 398 | void VKBlitScreen::CreateRenderPass() { | 411 | void VKBlitScreen::CreateRenderPass() { |
| 399 | VkAttachmentDescription color_attachment; | 412 | const VkAttachmentDescription color_attachment{ |
| 400 | color_attachment.flags = 0; | 413 | .flags = 0, |
| 401 | color_attachment.format = swapchain.GetImageFormat(); | 414 | .format = swapchain.GetImageFormat(), |
| 402 | color_attachment.samples = VK_SAMPLE_COUNT_1_BIT; | 415 | .samples = VK_SAMPLE_COUNT_1_BIT, |
| 403 | color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; | 416 | .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, |
| 404 | color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; | 417 | .storeOp = VK_ATTACHMENT_STORE_OP_STORE, |
| 405 | color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; | 418 | .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, |
| 406 | color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; | 419 | .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, |
| 407 | color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | 420 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, |
| 408 | color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; | 421 | .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, |
| 409 | 422 | }; | |
| 410 | VkAttachmentReference color_attachment_ref; | 423 | |
| 411 | color_attachment_ref.attachment = 0; | 424 | const VkAttachmentReference color_attachment_ref{ |
| 412 | color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; | 425 | .attachment = 0, |
| 413 | 426 | .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, | |
| 414 | VkSubpassDescription subpass_description; | 427 | }; |
| 415 | subpass_description.flags = 0; | 428 | |
| 416 | subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; | 429 | const VkSubpassDescription subpass_description{ |
| 417 | subpass_description.inputAttachmentCount = 0; | 430 | .flags = 0, |
| 418 | subpass_description.pInputAttachments = nullptr; | 431 | .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, |
| 419 | subpass_description.colorAttachmentCount = 1; | 432 | .inputAttachmentCount = 0, |
| 420 | subpass_description.pColorAttachments = &color_attachment_ref; | 433 | .pInputAttachments = nullptr, |
| 421 | subpass_description.pResolveAttachments = nullptr; | 434 | .colorAttachmentCount = 1, |
| 422 | subpass_description.pDepthStencilAttachment = nullptr; | 435 | .pColorAttachments = &color_attachment_ref, |
| 423 | subpass_description.preserveAttachmentCount = 0; | 436 | .pResolveAttachments = nullptr, |
| 424 | subpass_description.pPreserveAttachments = nullptr; | 437 | .pDepthStencilAttachment = nullptr, |
| 425 | 438 | .preserveAttachmentCount = 0, | |
| 426 | VkSubpassDependency dependency; | 439 | .pPreserveAttachments = nullptr, |
| 427 | dependency.srcSubpass = VK_SUBPASS_EXTERNAL; | 440 | }; |
| 428 | dependency.dstSubpass = 0; | 441 | |
| 429 | dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; | 442 | const VkSubpassDependency dependency{ |
| 430 | dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; | 443 | .srcSubpass = VK_SUBPASS_EXTERNAL, |
| 431 | dependency.srcAccessMask = 0; | 444 | .dstSubpass = 0, |
| 432 | dependency.dstAccessMask = | 445 | .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, |
| 433 | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; | 446 | .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, |
| 434 | dependency.dependencyFlags = 0; | 447 | .srcAccessMask = 0, |
| 435 | 448 | .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, | |
| 436 | VkRenderPassCreateInfo renderpass_ci; | 449 | .dependencyFlags = 0, |
| 437 | renderpass_ci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; | 450 | }; |
| 438 | renderpass_ci.pNext = nullptr; | 451 | |
| 439 | renderpass_ci.flags = 0; | 452 | const VkRenderPassCreateInfo renderpass_ci{ |
| 440 | renderpass_ci.attachmentCount = 1; | 453 | .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, |
| 441 | renderpass_ci.pAttachments = &color_attachment; | 454 | .pNext = nullptr, |
| 442 | renderpass_ci.subpassCount = 1; | 455 | .flags = 0, |
| 443 | renderpass_ci.pSubpasses = &subpass_description; | 456 | .attachmentCount = 1, |
| 444 | renderpass_ci.dependencyCount = 1; | 457 | .pAttachments = &color_attachment, |
| 445 | renderpass_ci.pDependencies = &dependency; | 458 | .subpassCount = 1, |
| 459 | .pSubpasses = &subpass_description, | ||
| 460 | .dependencyCount = 1, | ||
| 461 | .pDependencies = &dependency, | ||
| 462 | }; | ||
| 446 | 463 | ||
| 447 | renderpass = device.GetLogical().CreateRenderPass(renderpass_ci); | 464 | renderpass = device.GetLogical().CreateRenderPass(renderpass_ci); |
| 448 | } | 465 | } |
| 449 | 466 | ||
| 450 | void VKBlitScreen::CreateDescriptorSetLayout() { | 467 | void VKBlitScreen::CreateDescriptorSetLayout() { |
| 451 | std::array<VkDescriptorSetLayoutBinding, 2> layout_bindings; | 468 | const std::array<VkDescriptorSetLayoutBinding, 2> layout_bindings{{ |
| 452 | layout_bindings[0].binding = 0; | 469 | { |
| 453 | layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; | 470 | .binding = 0, |
| 454 | layout_bindings[0].descriptorCount = 1; | 471 | .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, |
| 455 | layout_bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; | 472 | .descriptorCount = 1, |
| 456 | layout_bindings[0].pImmutableSamplers = nullptr; | 473 | .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, |
| 457 | layout_bindings[1].binding = 1; | 474 | .pImmutableSamplers = nullptr, |
| 458 | layout_bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; | 475 | }, |
| 459 | layout_bindings[1].descriptorCount = 1; | 476 | { |
| 460 | layout_bindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; | 477 | .binding = 1, |
| 461 | layout_bindings[1].pImmutableSamplers = nullptr; | 478 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| 462 | 479 | .descriptorCount = 1, | |
| 463 | VkDescriptorSetLayoutCreateInfo ci; | 480 | .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, |
| 464 | ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; | 481 | .pImmutableSamplers = nullptr, |
| 465 | ci.pNext = nullptr; | 482 | }, |
| 466 | ci.flags = 0; | 483 | }}; |
| 467 | ci.bindingCount = static_cast<u32>(layout_bindings.size()); | 484 | |
| 468 | ci.pBindings = layout_bindings.data(); | 485 | const VkDescriptorSetLayoutCreateInfo ci{ |
| 486 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, | ||
| 487 | .pNext = nullptr, | ||
| 488 | .flags = 0, | ||
| 489 | .bindingCount = static_cast<u32>(layout_bindings.size()), | ||
| 490 | .pBindings = layout_bindings.data(), | ||
| 491 | }; | ||
| 469 | 492 | ||
| 470 | descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(ci); | 493 | descriptor_set_layout = device.GetLogical().CreateDescriptorSetLayout(ci); |
| 471 | } | 494 | } |
| @@ -473,175 +496,192 @@ void VKBlitScreen::CreateDescriptorSetLayout() { | |||
| 473 | void VKBlitScreen::CreateDescriptorSets() { | 496 | void VKBlitScreen::CreateDescriptorSets() { |
| 474 | const std::vector layouts(image_count, *descriptor_set_layout); | 497 | const std::vector layouts(image_count, *descriptor_set_layout); |
| 475 | 498 | ||
| 476 | VkDescriptorSetAllocateInfo ai; | 499 | const VkDescriptorSetAllocateInfo ai{ |
| 477 | ai.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; | 500 | .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, |
| 478 | ai.pNext = nullptr; | 501 | .pNext = nullptr, |
| 479 | ai.descriptorPool = *descriptor_pool; | 502 | .descriptorPool = *descriptor_pool, |
| 480 | ai.descriptorSetCount = static_cast<u32>(image_count); | 503 | .descriptorSetCount = static_cast<u32>(image_count), |
| 481 | ai.pSetLayouts = layouts.data(); | 504 | .pSetLayouts = layouts.data(), |
| 505 | }; | ||
| 506 | |||
| 482 | descriptor_sets = descriptor_pool.Allocate(ai); | 507 | descriptor_sets = descriptor_pool.Allocate(ai); |
| 483 | } | 508 | } |
| 484 | 509 | ||
| 485 | void VKBlitScreen::CreatePipelineLayout() { | 510 | void VKBlitScreen::CreatePipelineLayout() { |
| 486 | VkPipelineLayoutCreateInfo ci; | 511 | const VkPipelineLayoutCreateInfo ci{ |
| 487 | ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; | 512 | .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, |
| 488 | ci.pNext = nullptr; | 513 | .pNext = nullptr, |
| 489 | ci.flags = 0; | 514 | .flags = 0, |
| 490 | ci.setLayoutCount = 1; | 515 | .setLayoutCount = 1, |
| 491 | ci.pSetLayouts = descriptor_set_layout.address(); | 516 | .pSetLayouts = descriptor_set_layout.address(), |
| 492 | ci.pushConstantRangeCount = 0; | 517 | .pushConstantRangeCount = 0, |
| 493 | ci.pPushConstantRanges = nullptr; | 518 | .pPushConstantRanges = nullptr, |
| 519 | }; | ||
| 494 | pipeline_layout = device.GetLogical().CreatePipelineLayout(ci); | 520 | pipeline_layout = device.GetLogical().CreatePipelineLayout(ci); |
| 495 | } | 521 | } |
| 496 | 522 | ||
| 497 | void VKBlitScreen::CreateGraphicsPipeline() { | 523 | void VKBlitScreen::CreateGraphicsPipeline() { |
| 498 | std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages; | 524 | const std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{{ |
| 499 | shader_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; | 525 | { |
| 500 | shader_stages[0].pNext = nullptr; | 526 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, |
| 501 | shader_stages[0].flags = 0; | 527 | .pNext = nullptr, |
| 502 | shader_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; | 528 | .flags = 0, |
| 503 | shader_stages[0].module = *vertex_shader; | 529 | .stage = VK_SHADER_STAGE_VERTEX_BIT, |
| 504 | shader_stages[0].pName = "main"; | 530 | .module = *vertex_shader, |
| 505 | shader_stages[0].pSpecializationInfo = nullptr; | 531 | .pName = "main", |
| 506 | shader_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; | 532 | .pSpecializationInfo = nullptr, |
| 507 | shader_stages[1].pNext = nullptr; | 533 | }, |
| 508 | shader_stages[1].flags = 0; | 534 | { |
| 509 | shader_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; | 535 | .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, |
| 510 | shader_stages[1].module = *fragment_shader; | 536 | .pNext = nullptr, |
| 511 | shader_stages[1].pName = "main"; | 537 | .flags = 0, |
| 512 | shader_stages[1].pSpecializationInfo = nullptr; | 538 | .stage = VK_SHADER_STAGE_FRAGMENT_BIT, |
| 539 | .module = *fragment_shader, | ||
| 540 | .pName = "main", | ||
| 541 | .pSpecializationInfo = nullptr, | ||
| 542 | }, | ||
| 543 | }}; | ||
| 513 | 544 | ||
| 514 | const auto vertex_binding_description = ScreenRectVertex::GetDescription(); | 545 | const auto vertex_binding_description = ScreenRectVertex::GetDescription(); |
| 515 | const auto vertex_attrs_description = ScreenRectVertex::GetAttributes(); | 546 | const auto vertex_attrs_description = ScreenRectVertex::GetAttributes(); |
| 516 | 547 | ||
| 517 | VkPipelineVertexInputStateCreateInfo vertex_input_ci; | 548 | const VkPipelineVertexInputStateCreateInfo vertex_input_ci{ |
| 518 | vertex_input_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; | 549 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, |
| 519 | vertex_input_ci.pNext = nullptr; | 550 | .pNext = nullptr, |
| 520 | vertex_input_ci.flags = 0; | 551 | .flags = 0, |
| 521 | vertex_input_ci.vertexBindingDescriptionCount = 1; | 552 | .vertexBindingDescriptionCount = 1, |
| 522 | vertex_input_ci.pVertexBindingDescriptions = &vertex_binding_description; | 553 | .pVertexBindingDescriptions = &vertex_binding_description, |
| 523 | vertex_input_ci.vertexAttributeDescriptionCount = u32{vertex_attrs_description.size()}; | 554 | .vertexAttributeDescriptionCount = u32{vertex_attrs_description.size()}, |
| 524 | vertex_input_ci.pVertexAttributeDescriptions = vertex_attrs_description.data(); | 555 | .pVertexAttributeDescriptions = vertex_attrs_description.data(), |
| 525 | 556 | }; | |
| 526 | VkPipelineInputAssemblyStateCreateInfo input_assembly_ci; | 557 | |
| 527 | input_assembly_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; | 558 | const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{ |
| 528 | input_assembly_ci.pNext = nullptr; | 559 | .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, |
| 529 | input_assembly_ci.flags = 0; | 560 | .pNext = nullptr, |
| 530 | input_assembly_ci.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; | 561 | .flags = 0, |
| 531 | input_assembly_ci.primitiveRestartEnable = VK_FALSE; | 562 | .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, |
| 532 | 563 | .primitiveRestartEnable = VK_FALSE, | |
| 533 | VkPipelineViewportStateCreateInfo viewport_state_ci; | 564 | }; |
| 534 | viewport_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; | 565 | |
| 535 | viewport_state_ci.pNext = nullptr; | 566 | const VkPipelineViewportStateCreateInfo viewport_state_ci{ |
| 536 | viewport_state_ci.flags = 0; | 567 | .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, |
| 537 | viewport_state_ci.viewportCount = 1; | 568 | .pNext = nullptr, |
| 538 | viewport_state_ci.pViewports = nullptr; | 569 | .flags = 0, |
| 539 | viewport_state_ci.scissorCount = 1; | 570 | .viewportCount = 1, |
| 540 | viewport_state_ci.pScissors = nullptr; | 571 | .pViewports = nullptr, |
| 541 | 572 | .scissorCount = 1, | |
| 542 | VkPipelineRasterizationStateCreateInfo rasterization_ci; | 573 | .pScissors = nullptr, |
| 543 | rasterization_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; | 574 | }; |
| 544 | rasterization_ci.pNext = nullptr; | 575 | |
| 545 | rasterization_ci.flags = 0; | 576 | const VkPipelineRasterizationStateCreateInfo rasterization_ci{ |
| 546 | rasterization_ci.depthClampEnable = VK_FALSE; | 577 | .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, |
| 547 | rasterization_ci.rasterizerDiscardEnable = VK_FALSE; | 578 | .pNext = nullptr, |
| 548 | rasterization_ci.polygonMode = VK_POLYGON_MODE_FILL; | 579 | .flags = 0, |
| 549 | rasterization_ci.cullMode = VK_CULL_MODE_NONE; | 580 | .depthClampEnable = VK_FALSE, |
| 550 | rasterization_ci.frontFace = VK_FRONT_FACE_CLOCKWISE; | 581 | .rasterizerDiscardEnable = VK_FALSE, |
| 551 | rasterization_ci.depthBiasEnable = VK_FALSE; | 582 | .polygonMode = VK_POLYGON_MODE_FILL, |
| 552 | rasterization_ci.depthBiasConstantFactor = 0.0f; | 583 | .cullMode = VK_CULL_MODE_NONE, |
| 553 | rasterization_ci.depthBiasClamp = 0.0f; | 584 | .frontFace = VK_FRONT_FACE_CLOCKWISE, |
| 554 | rasterization_ci.depthBiasSlopeFactor = 0.0f; | 585 | .depthBiasEnable = VK_FALSE, |
| 555 | rasterization_ci.lineWidth = 1.0f; | 586 | .depthBiasConstantFactor = 0.0f, |
| 556 | 587 | .depthBiasClamp = 0.0f, | |
| 557 | VkPipelineMultisampleStateCreateInfo multisampling_ci; | 588 | .depthBiasSlopeFactor = 0.0f, |
| 558 | multisampling_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; | 589 | .lineWidth = 1.0f, |
| 559 | multisampling_ci.pNext = nullptr; | 590 | }; |
| 560 | multisampling_ci.flags = 0; | 591 | |
| 561 | multisampling_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; | 592 | const VkPipelineMultisampleStateCreateInfo multisampling_ci{ |
| 562 | multisampling_ci.sampleShadingEnable = VK_FALSE; | 593 | .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, |
| 563 | multisampling_ci.minSampleShading = 0.0f; | 594 | .pNext = nullptr, |
| 564 | multisampling_ci.pSampleMask = nullptr; | 595 | .flags = 0, |
| 565 | multisampling_ci.alphaToCoverageEnable = VK_FALSE; | 596 | .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, |
| 566 | multisampling_ci.alphaToOneEnable = VK_FALSE; | 597 | .sampleShadingEnable = VK_FALSE, |
| 567 | 598 | .minSampleShading = 0.0f, | |
| 568 | VkPipelineColorBlendAttachmentState color_blend_attachment; | 599 | .pSampleMask = nullptr, |
| 569 | color_blend_attachment.blendEnable = VK_FALSE; | 600 | .alphaToCoverageEnable = VK_FALSE, |
| 570 | color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO; | 601 | .alphaToOneEnable = VK_FALSE, |
| 571 | color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; | 602 | }; |
| 572 | color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD; | 603 | |
| 573 | color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; | 604 | const VkPipelineColorBlendAttachmentState color_blend_attachment{ |
| 574 | color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; | 605 | .blendEnable = VK_FALSE, |
| 575 | color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD; | 606 | .srcColorBlendFactor = VK_BLEND_FACTOR_ZERO, |
| 576 | color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | | 607 | .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO, |
| 577 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; | 608 | .colorBlendOp = VK_BLEND_OP_ADD, |
| 578 | 609 | .srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, | |
| 579 | VkPipelineColorBlendStateCreateInfo color_blend_ci; | 610 | .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, |
| 580 | color_blend_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; | 611 | .alphaBlendOp = VK_BLEND_OP_ADD, |
| 581 | color_blend_ci.flags = 0; | 612 | .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | |
| 582 | color_blend_ci.pNext = nullptr; | 613 | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT, |
| 583 | color_blend_ci.logicOpEnable = VK_FALSE; | 614 | }; |
| 584 | color_blend_ci.logicOp = VK_LOGIC_OP_COPY; | 615 | |
| 585 | color_blend_ci.attachmentCount = 1; | 616 | const VkPipelineColorBlendStateCreateInfo color_blend_ci{ |
| 586 | color_blend_ci.pAttachments = &color_blend_attachment; | 617 | .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, |
| 587 | color_blend_ci.blendConstants[0] = 0.0f; | 618 | .pNext = nullptr, |
| 588 | color_blend_ci.blendConstants[1] = 0.0f; | 619 | .flags = 0, |
| 589 | color_blend_ci.blendConstants[2] = 0.0f; | 620 | .logicOpEnable = VK_FALSE, |
| 590 | color_blend_ci.blendConstants[3] = 0.0f; | 621 | .logicOp = VK_LOGIC_OP_COPY, |
| 591 | 622 | .attachmentCount = 1, | |
| 592 | static constexpr std::array dynamic_states = {VK_DYNAMIC_STATE_VIEWPORT, | 623 | .pAttachments = &color_blend_attachment, |
| 593 | VK_DYNAMIC_STATE_SCISSOR}; | 624 | .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}, |
| 594 | VkPipelineDynamicStateCreateInfo dynamic_state_ci; | 625 | }; |
| 595 | dynamic_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; | 626 | |
| 596 | dynamic_state_ci.pNext = nullptr; | 627 | static constexpr std::array dynamic_states{ |
| 597 | dynamic_state_ci.flags = 0; | 628 | VK_DYNAMIC_STATE_VIEWPORT, |
| 598 | dynamic_state_ci.dynamicStateCount = static_cast<u32>(dynamic_states.size()); | 629 | VK_DYNAMIC_STATE_SCISSOR, |
| 599 | dynamic_state_ci.pDynamicStates = dynamic_states.data(); | 630 | }; |
| 600 | 631 | const VkPipelineDynamicStateCreateInfo dynamic_state_ci{ | |
| 601 | VkGraphicsPipelineCreateInfo pipeline_ci; | 632 | .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, |
| 602 | pipeline_ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; | 633 | .pNext = nullptr, |
| 603 | pipeline_ci.pNext = nullptr; | 634 | .flags = 0, |
| 604 | pipeline_ci.flags = 0; | 635 | .dynamicStateCount = static_cast<u32>(dynamic_states.size()), |
| 605 | pipeline_ci.stageCount = static_cast<u32>(shader_stages.size()); | 636 | .pDynamicStates = dynamic_states.data(), |
| 606 | pipeline_ci.pStages = shader_stages.data(); | 637 | }; |
| 607 | pipeline_ci.pVertexInputState = &vertex_input_ci; | 638 | |
| 608 | pipeline_ci.pInputAssemblyState = &input_assembly_ci; | 639 | const VkGraphicsPipelineCreateInfo pipeline_ci{ |
| 609 | pipeline_ci.pTessellationState = nullptr; | 640 | .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, |
| 610 | pipeline_ci.pViewportState = &viewport_state_ci; | 641 | .pNext = nullptr, |
| 611 | pipeline_ci.pRasterizationState = &rasterization_ci; | 642 | .flags = 0, |
| 612 | pipeline_ci.pMultisampleState = &multisampling_ci; | 643 | .stageCount = static_cast<u32>(shader_stages.size()), |
| 613 | pipeline_ci.pDepthStencilState = nullptr; | 644 | .pStages = shader_stages.data(), |
| 614 | pipeline_ci.pColorBlendState = &color_blend_ci; | 645 | .pVertexInputState = &vertex_input_ci, |
| 615 | pipeline_ci.pDynamicState = &dynamic_state_ci; | 646 | .pInputAssemblyState = &input_assembly_ci, |
| 616 | pipeline_ci.layout = *pipeline_layout; | 647 | .pTessellationState = nullptr, |
| 617 | pipeline_ci.renderPass = *renderpass; | 648 | .pViewportState = &viewport_state_ci, |
| 618 | pipeline_ci.subpass = 0; | 649 | .pRasterizationState = &rasterization_ci, |
| 619 | pipeline_ci.basePipelineHandle = 0; | 650 | .pMultisampleState = &multisampling_ci, |
| 620 | pipeline_ci.basePipelineIndex = 0; | 651 | .pDepthStencilState = nullptr, |
| 652 | .pColorBlendState = &color_blend_ci, | ||
| 653 | .pDynamicState = &dynamic_state_ci, | ||
| 654 | .layout = *pipeline_layout, | ||
| 655 | .renderPass = *renderpass, | ||
| 656 | .subpass = 0, | ||
| 657 | .basePipelineHandle = 0, | ||
| 658 | .basePipelineIndex = 0, | ||
| 659 | }; | ||
| 621 | 660 | ||
| 622 | pipeline = device.GetLogical().CreateGraphicsPipeline(pipeline_ci); | 661 | pipeline = device.GetLogical().CreateGraphicsPipeline(pipeline_ci); |
| 623 | } | 662 | } |
| 624 | 663 | ||
| 625 | void VKBlitScreen::CreateSampler() { | 664 | void VKBlitScreen::CreateSampler() { |
| 626 | VkSamplerCreateInfo ci; | 665 | const VkSamplerCreateInfo ci{ |
| 627 | ci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; | 666 | .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, |
| 628 | ci.pNext = nullptr; | 667 | .pNext = nullptr, |
| 629 | ci.flags = 0; | 668 | .flags = 0, |
| 630 | ci.magFilter = VK_FILTER_LINEAR; | 669 | .magFilter = VK_FILTER_LINEAR, |
| 631 | ci.minFilter = VK_FILTER_NEAREST; | 670 | .minFilter = VK_FILTER_NEAREST, |
| 632 | ci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; | 671 | .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR, |
| 633 | ci.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; | 672 | .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, |
| 634 | ci.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; | 673 | .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, |
| 635 | ci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; | 674 | .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, |
| 636 | ci.mipLodBias = 0.0f; | 675 | .mipLodBias = 0.0f, |
| 637 | ci.anisotropyEnable = VK_FALSE; | 676 | .anisotropyEnable = VK_FALSE, |
| 638 | ci.maxAnisotropy = 0.0f; | 677 | .maxAnisotropy = 0.0f, |
| 639 | ci.compareEnable = VK_FALSE; | 678 | .compareEnable = VK_FALSE, |
| 640 | ci.compareOp = VK_COMPARE_OP_NEVER; | 679 | .compareOp = VK_COMPARE_OP_NEVER, |
| 641 | ci.minLod = 0.0f; | 680 | .minLod = 0.0f, |
| 642 | ci.maxLod = 0.0f; | 681 | .maxLod = 0.0f, |
| 643 | ci.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; | 682 | .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, |
| 644 | ci.unnormalizedCoordinates = VK_FALSE; | 683 | .unnormalizedCoordinates = VK_FALSE, |
| 684 | }; | ||
| 645 | 685 | ||
| 646 | sampler = device.GetLogical().CreateSampler(ci); | 686 | sampler = device.GetLogical().CreateSampler(ci); |
| 647 | } | 687 | } |
| @@ -650,15 +690,16 @@ void VKBlitScreen::CreateFramebuffers() { | |||
| 650 | const VkExtent2D size{swapchain.GetSize()}; | 690 | const VkExtent2D size{swapchain.GetSize()}; |
| 651 | framebuffers.resize(image_count); | 691 | framebuffers.resize(image_count); |
| 652 | 692 | ||
| 653 | VkFramebufferCreateInfo ci; | 693 | VkFramebufferCreateInfo ci{ |
| 654 | ci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; | 694 | .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, |
| 655 | ci.pNext = nullptr; | 695 | .pNext = nullptr, |
| 656 | ci.flags = 0; | 696 | .flags = 0, |
| 657 | ci.renderPass = *renderpass; | 697 | .renderPass = *renderpass, |
| 658 | ci.attachmentCount = 1; | 698 | .attachmentCount = 1, |
| 659 | ci.width = size.width; | 699 | .width = size.width, |
| 660 | ci.height = size.height; | 700 | .height = size.height, |
| 661 | ci.layers = 1; | 701 | .layers = 1, |
| 702 | }; | ||
| 662 | 703 | ||
| 663 | for (std::size_t i = 0; i < image_count; ++i) { | 704 | for (std::size_t i = 0; i < image_count; ++i) { |
| 664 | const VkImageView image_view{swapchain.GetImageViewIndex(i)}; | 705 | const VkImageView image_view{swapchain.GetImageViewIndex(i)}; |
| @@ -678,16 +719,17 @@ void VKBlitScreen::ReleaseRawImages() { | |||
| 678 | } | 719 | } |
| 679 | 720 | ||
| 680 | void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { | 721 | void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { |
| 681 | VkBufferCreateInfo ci; | 722 | const VkBufferCreateInfo ci{ |
| 682 | ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; | 723 | .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, |
| 683 | ci.pNext = nullptr; | 724 | .pNext = nullptr, |
| 684 | ci.flags = 0; | 725 | .flags = 0, |
| 685 | ci.size = CalculateBufferSize(framebuffer); | 726 | .size = CalculateBufferSize(framebuffer), |
| 686 | ci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | | 727 | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | |
| 687 | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; | 728 | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, |
| 688 | ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; | 729 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 689 | ci.queueFamilyIndexCount = 0; | 730 | .queueFamilyIndexCount = 0, |
| 690 | ci.pQueueFamilyIndices = nullptr; | 731 | .pQueueFamilyIndices = nullptr, |
| 732 | }; | ||
| 691 | 733 | ||
| 692 | buffer = device.GetLogical().CreateBuffer(ci); | 734 | buffer = device.GetLogical().CreateBuffer(ci); |
| 693 | buffer_commit = memory_manager.Commit(buffer, true); | 735 | buffer_commit = memory_manager.Commit(buffer, true); |
| @@ -697,24 +739,28 @@ void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) | |||
| 697 | raw_images.resize(image_count); | 739 | raw_images.resize(image_count); |
| 698 | raw_buffer_commits.resize(image_count); | 740 | raw_buffer_commits.resize(image_count); |
| 699 | 741 | ||
| 700 | VkImageCreateInfo ci; | 742 | const VkImageCreateInfo ci{ |
| 701 | ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; | 743 | .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, |
| 702 | ci.pNext = nullptr; | 744 | .pNext = nullptr, |
| 703 | ci.flags = 0; | 745 | .flags = 0, |
| 704 | ci.imageType = VK_IMAGE_TYPE_2D; | 746 | .imageType = VK_IMAGE_TYPE_2D, |
| 705 | ci.format = GetFormat(framebuffer); | 747 | .format = GetFormat(framebuffer), |
| 706 | ci.extent.width = framebuffer.width; | 748 | .extent = |
| 707 | ci.extent.height = framebuffer.height; | 749 | { |
| 708 | ci.extent.depth = 1; | 750 | .width = framebuffer.width, |
| 709 | ci.mipLevels = 1; | 751 | .height = framebuffer.height, |
| 710 | ci.arrayLayers = 1; | 752 | .depth = 1, |
| 711 | ci.samples = VK_SAMPLE_COUNT_1_BIT; | 753 | }, |
| 712 | ci.tiling = VK_IMAGE_TILING_LINEAR; | 754 | .mipLevels = 1, |
| 713 | ci.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; | 755 | .arrayLayers = 1, |
| 714 | ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; | 756 | .samples = VK_SAMPLE_COUNT_1_BIT, |
| 715 | ci.queueFamilyIndexCount = 0; | 757 | .tiling = VK_IMAGE_TILING_LINEAR, |
| 716 | ci.pQueueFamilyIndices = nullptr; | 758 | .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, |
| 717 | ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | 759 | .sharingMode = VK_SHARING_MODE_EXCLUSIVE, |
| 760 | .queueFamilyIndexCount = 0, | ||
| 761 | .pQueueFamilyIndices = nullptr, | ||
| 762 | .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, | ||
| 763 | }; | ||
| 718 | 764 | ||
| 719 | for (std::size_t i = 0; i < image_count; ++i) { | 765 | for (std::size_t i = 0; i < image_count; ++i) { |
| 720 | raw_images[i] = std::make_unique<VKImage>(device, scheduler, ci, VK_IMAGE_ASPECT_COLOR_BIT); | 766 | 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) | |||
| 723 | } | 769 | } |
| 724 | 770 | ||
| 725 | void VKBlitScreen::UpdateDescriptorSet(std::size_t image_index, VkImageView image_view) const { | 771 | void VKBlitScreen::UpdateDescriptorSet(std::size_t image_index, VkImageView image_view) const { |
| 726 | VkDescriptorBufferInfo buffer_info; | 772 | const VkDescriptorBufferInfo buffer_info{ |
| 727 | buffer_info.buffer = *buffer; | 773 | .buffer = *buffer, |
| 728 | buffer_info.offset = offsetof(BufferData, uniform); | 774 | .offset = offsetof(BufferData, uniform), |
| 729 | buffer_info.range = sizeof(BufferData::uniform); | 775 | .range = sizeof(BufferData::uniform), |
| 730 | 776 | }; | |
| 731 | VkWriteDescriptorSet ubo_write; | 777 | |
| 732 | ubo_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; | 778 | const VkWriteDescriptorSet ubo_write{ |
| 733 | ubo_write.pNext = nullptr; | 779 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, |
| 734 | ubo_write.dstSet = descriptor_sets[image_index]; | 780 | .pNext = nullptr, |
| 735 | ubo_write.dstBinding = 0; | 781 | .dstSet = descriptor_sets[image_index], |
| 736 | ubo_write.dstArrayElement = 0; | 782 | .dstBinding = 0, |
| 737 | ubo_write.descriptorCount = 1; | 783 | .dstArrayElement = 0, |
| 738 | ubo_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; | 784 | .descriptorCount = 1, |
| 739 | ubo_write.pImageInfo = nullptr; | 785 | .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, |
| 740 | ubo_write.pBufferInfo = &buffer_info; | 786 | .pImageInfo = nullptr, |
| 741 | ubo_write.pTexelBufferView = nullptr; | 787 | .pBufferInfo = &buffer_info, |
| 742 | 788 | .pTexelBufferView = nullptr, | |
| 743 | VkDescriptorImageInfo image_info; | 789 | }; |
| 744 | image_info.sampler = *sampler; | 790 | |
| 745 | image_info.imageView = image_view; | 791 | const VkDescriptorImageInfo image_info{ |
| 746 | image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; | 792 | .sampler = *sampler, |
| 747 | 793 | .imageView = image_view, | |
| 748 | VkWriteDescriptorSet sampler_write; | 794 | .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, |
| 749 | sampler_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; | 795 | }; |
| 750 | sampler_write.pNext = nullptr; | 796 | |
| 751 | sampler_write.dstSet = descriptor_sets[image_index]; | 797 | const VkWriteDescriptorSet sampler_write{ |
| 752 | sampler_write.dstBinding = 1; | 798 | .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, |
| 753 | sampler_write.dstArrayElement = 0; | 799 | .pNext = nullptr, |
| 754 | sampler_write.descriptorCount = 1; | 800 | .dstSet = descriptor_sets[image_index], |
| 755 | sampler_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; | 801 | .dstBinding = 1, |
| 756 | sampler_write.pImageInfo = &image_info; | 802 | .dstArrayElement = 0, |
| 757 | sampler_write.pBufferInfo = nullptr; | 803 | .descriptorCount = 1, |
| 758 | sampler_write.pTexelBufferView = nullptr; | 804 | .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, |
| 805 | .pImageInfo = &image_info, | ||
| 806 | .pBufferInfo = nullptr, | ||
| 807 | .pTexelBufferView = nullptr, | ||
| 808 | }; | ||
| 759 | 809 | ||
| 760 | device.GetLogical().UpdateDescriptorSets(std::array{ubo_write, sampler_write}, {}); | 810 | device.GetLogical().UpdateDescriptorSets(std::array{ubo_write, sampler_write}, {}); |
| 761 | } | 811 | } |
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 { | |||
| 22 | 22 | ||
| 23 | namespace Alternatives { | 23 | namespace Alternatives { |
| 24 | 24 | ||
| 25 | constexpr std::array Depth24UnormS8_UINT = {VK_FORMAT_D32_SFLOAT_S8_UINT, | 25 | constexpr std::array Depth24UnormS8_UINT{ |
| 26 | VK_FORMAT_D16_UNORM_S8_UINT, VkFormat{}}; | 26 | VK_FORMAT_D32_SFLOAT_S8_UINT, |
| 27 | constexpr std::array Depth16UnormS8_UINT = {VK_FORMAT_D24_UNORM_S8_UINT, | 27 | VK_FORMAT_D16_UNORM_S8_UINT, |
| 28 | VK_FORMAT_D32_SFLOAT_S8_UINT, VkFormat{}}; | 28 | VkFormat{}, |
| 29 | }; | ||
| 30 | |||
| 31 | constexpr std::array Depth16UnormS8_UINT{ | ||
| 32 | VK_FORMAT_D24_UNORM_S8_UINT, | ||
| 33 | VK_FORMAT_D32_SFLOAT_S8_UINT, | ||
| 34 | VkFormat{}, | ||
| 35 | }; | ||
| 29 | 36 | ||
| 30 | } // namespace Alternatives | 37 | } // namespace Alternatives |
| 31 | 38 | ||
| 32 | constexpr std::array REQUIRED_EXTENSIONS = { | 39 | constexpr std::array REQUIRED_EXTENSIONS{ |
| 33 | VK_KHR_SWAPCHAIN_EXTENSION_NAME, | 40 | VK_KHR_SWAPCHAIN_EXTENSION_NAME, |
| 34 | VK_KHR_16BIT_STORAGE_EXTENSION_NAME, | 41 | VK_KHR_16BIT_STORAGE_EXTENSION_NAME, |
| 35 | VK_KHR_8BIT_STORAGE_EXTENSION_NAME, | 42 | VK_KHR_8BIT_STORAGE_EXTENSION_NAME, |
| @@ -169,97 +176,104 @@ bool VKDevice::Create() { | |||
| 169 | const auto queue_cis = GetDeviceQueueCreateInfos(); | 176 | const auto queue_cis = GetDeviceQueueCreateInfos(); |
| 170 | const std::vector extensions = LoadExtensions(); | 177 | const std::vector extensions = LoadExtensions(); |
| 171 | 178 | ||
| 172 | VkPhysicalDeviceFeatures2 features2; | 179 | VkPhysicalDeviceFeatures2 features2{ |
| 173 | features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; | 180 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, |
| 174 | features2.pNext = nullptr; | 181 | .pNext = nullptr, |
| 182 | }; | ||
| 175 | const void* first_next = &features2; | 183 | const void* first_next = &features2; |
| 176 | void** next = &features2.pNext; | 184 | void** next = &features2.pNext; |
| 177 | 185 | ||
| 178 | auto& features = features2.features; | 186 | features2.features = { |
| 179 | features.robustBufferAccess = false; | 187 | .robustBufferAccess = false, |
| 180 | features.fullDrawIndexUint32 = false; | 188 | .fullDrawIndexUint32 = false, |
| 181 | features.imageCubeArray = false; | 189 | .imageCubeArray = false, |
| 182 | features.independentBlend = true; | 190 | .independentBlend = true, |
| 183 | features.geometryShader = true; | 191 | .geometryShader = true, |
| 184 | features.tessellationShader = true; | 192 | .tessellationShader = true, |
| 185 | features.sampleRateShading = false; | 193 | .sampleRateShading = false, |
| 186 | features.dualSrcBlend = false; | 194 | .dualSrcBlend = false, |
| 187 | features.logicOp = false; | 195 | .logicOp = false, |
| 188 | features.multiDrawIndirect = false; | 196 | .multiDrawIndirect = false, |
| 189 | features.drawIndirectFirstInstance = false; | 197 | .drawIndirectFirstInstance = false, |
| 190 | features.depthClamp = true; | 198 | .depthClamp = true, |
| 191 | features.depthBiasClamp = true; | 199 | .depthBiasClamp = true, |
| 192 | features.fillModeNonSolid = false; | 200 | .fillModeNonSolid = false, |
| 193 | features.depthBounds = false; | 201 | .depthBounds = false, |
| 194 | features.wideLines = false; | 202 | .wideLines = false, |
| 195 | features.largePoints = true; | 203 | .largePoints = true, |
| 196 | features.alphaToOne = false; | 204 | .alphaToOne = false, |
| 197 | features.multiViewport = true; | 205 | .multiViewport = true, |
| 198 | features.samplerAnisotropy = true; | 206 | .samplerAnisotropy = true, |
| 199 | features.textureCompressionETC2 = false; | 207 | .textureCompressionETC2 = false, |
| 200 | features.textureCompressionASTC_LDR = is_optimal_astc_supported; | 208 | .textureCompressionASTC_LDR = is_optimal_astc_supported, |
| 201 | features.textureCompressionBC = false; | 209 | .textureCompressionBC = false, |
| 202 | features.occlusionQueryPrecise = true; | 210 | .occlusionQueryPrecise = true, |
| 203 | features.pipelineStatisticsQuery = false; | 211 | .pipelineStatisticsQuery = false, |
| 204 | features.vertexPipelineStoresAndAtomics = true; | 212 | .vertexPipelineStoresAndAtomics = true, |
| 205 | features.fragmentStoresAndAtomics = true; | 213 | .fragmentStoresAndAtomics = true, |
| 206 | features.shaderTessellationAndGeometryPointSize = false; | 214 | .shaderTessellationAndGeometryPointSize = false, |
| 207 | features.shaderImageGatherExtended = true; | 215 | .shaderImageGatherExtended = true, |
| 208 | features.shaderStorageImageExtendedFormats = false; | 216 | .shaderStorageImageExtendedFormats = false, |
| 209 | features.shaderStorageImageMultisample = false; | 217 | .shaderStorageImageMultisample = false, |
| 210 | features.shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported; | 218 | .shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported, |
| 211 | features.shaderStorageImageWriteWithoutFormat = true; | 219 | .shaderStorageImageWriteWithoutFormat = true, |
| 212 | features.shaderUniformBufferArrayDynamicIndexing = false; | 220 | .shaderUniformBufferArrayDynamicIndexing = false, |
| 213 | features.shaderSampledImageArrayDynamicIndexing = false; | 221 | .shaderSampledImageArrayDynamicIndexing = false, |
| 214 | features.shaderStorageBufferArrayDynamicIndexing = false; | 222 | .shaderStorageBufferArrayDynamicIndexing = false, |
| 215 | features.shaderStorageImageArrayDynamicIndexing = false; | 223 | .shaderStorageImageArrayDynamicIndexing = false, |
| 216 | features.shaderClipDistance = false; | 224 | .shaderClipDistance = false, |
| 217 | features.shaderCullDistance = false; | 225 | .shaderCullDistance = false, |
| 218 | features.shaderFloat64 = false; | 226 | .shaderFloat64 = false, |
| 219 | features.shaderInt64 = false; | 227 | .shaderInt64 = false, |
| 220 | features.shaderInt16 = false; | 228 | .shaderInt16 = false, |
| 221 | features.shaderResourceResidency = false; | 229 | .shaderResourceResidency = false, |
| 222 | features.shaderResourceMinLod = false; | 230 | .shaderResourceMinLod = false, |
| 223 | features.sparseBinding = false; | 231 | .sparseBinding = false, |
| 224 | features.sparseResidencyBuffer = false; | 232 | .sparseResidencyBuffer = false, |
| 225 | features.sparseResidencyImage2D = false; | 233 | .sparseResidencyImage2D = false, |
| 226 | features.sparseResidencyImage3D = false; | 234 | .sparseResidencyImage3D = false, |
| 227 | features.sparseResidency2Samples = false; | 235 | .sparseResidency2Samples = false, |
| 228 | features.sparseResidency4Samples = false; | 236 | .sparseResidency4Samples = false, |
| 229 | features.sparseResidency8Samples = false; | 237 | .sparseResidency8Samples = false, |
| 230 | features.sparseResidency16Samples = false; | 238 | .sparseResidency16Samples = false, |
| 231 | features.sparseResidencyAliased = false; | 239 | .sparseResidencyAliased = false, |
| 232 | features.variableMultisampleRate = false; | 240 | .variableMultisampleRate = false, |
| 233 | features.inheritedQueries = false; | 241 | .inheritedQueries = false, |
| 234 | 242 | }; | |
| 235 | VkPhysicalDevice16BitStorageFeaturesKHR bit16_storage; | 243 | |
| 236 | bit16_storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR; | 244 | VkPhysicalDevice16BitStorageFeaturesKHR bit16_storage{ |
| 237 | bit16_storage.pNext = nullptr; | 245 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR, |
| 238 | bit16_storage.storageBuffer16BitAccess = false; | 246 | .pNext = nullptr, |
| 239 | bit16_storage.uniformAndStorageBuffer16BitAccess = true; | 247 | .storageBuffer16BitAccess = false, |
| 240 | bit16_storage.storagePushConstant16 = false; | 248 | .uniformAndStorageBuffer16BitAccess = true, |
| 241 | bit16_storage.storageInputOutput16 = false; | 249 | .storagePushConstant16 = false, |
| 250 | .storageInputOutput16 = false, | ||
| 251 | }; | ||
| 242 | SetNext(next, bit16_storage); | 252 | SetNext(next, bit16_storage); |
| 243 | 253 | ||
| 244 | VkPhysicalDevice8BitStorageFeaturesKHR bit8_storage; | 254 | VkPhysicalDevice8BitStorageFeaturesKHR bit8_storage{ |
| 245 | bit8_storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR; | 255 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR, |
| 246 | bit8_storage.pNext = nullptr; | 256 | .pNext = nullptr, |
| 247 | bit8_storage.storageBuffer8BitAccess = false; | 257 | .storageBuffer8BitAccess = false, |
| 248 | bit8_storage.uniformAndStorageBuffer8BitAccess = true; | 258 | .uniformAndStorageBuffer8BitAccess = true, |
| 249 | bit8_storage.storagePushConstant8 = false; | 259 | .storagePushConstant8 = false, |
| 260 | }; | ||
| 250 | SetNext(next, bit8_storage); | 261 | SetNext(next, bit8_storage); |
| 251 | 262 | ||
| 252 | VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset; | 263 | VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset{ |
| 253 | host_query_reset.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT; | 264 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT, |
| 254 | host_query_reset.hostQueryReset = true; | 265 | .hostQueryReset = true, |
| 266 | }; | ||
| 255 | SetNext(next, host_query_reset); | 267 | SetNext(next, host_query_reset); |
| 256 | 268 | ||
| 257 | VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8; | 269 | VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8; |
| 258 | if (is_float16_supported) { | 270 | if (is_float16_supported) { |
| 259 | float16_int8.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR; | 271 | float16_int8 = { |
| 260 | float16_int8.pNext = nullptr; | 272 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR, |
| 261 | float16_int8.shaderFloat16 = true; | 273 | .pNext = nullptr, |
| 262 | float16_int8.shaderInt8 = false; | 274 | .shaderFloat16 = true, |
| 275 | .shaderInt8 = false, | ||
| 276 | }; | ||
| 263 | SetNext(next, float16_int8); | 277 | SetNext(next, float16_int8); |
| 264 | } else { | 278 | } else { |
| 265 | LOG_INFO(Render_Vulkan, "Device doesn't support float16 natively"); | 279 | LOG_INFO(Render_Vulkan, "Device doesn't support float16 natively"); |
| @@ -271,10 +285,11 @@ bool VKDevice::Create() { | |||
| 271 | 285 | ||
| 272 | VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR std430_layout; | 286 | VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR std430_layout; |
| 273 | if (khr_uniform_buffer_standard_layout) { | 287 | if (khr_uniform_buffer_standard_layout) { |
| 274 | std430_layout.sType = | 288 | std430_layout = { |
| 275 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR; | 289 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR, |
| 276 | std430_layout.pNext = nullptr; | 290 | .pNext = nullptr, |
| 277 | std430_layout.uniformBufferStandardLayout = true; | 291 | .uniformBufferStandardLayout = true, |
| 292 | }; | ||
| 278 | SetNext(next, std430_layout); | 293 | SetNext(next, std430_layout); |
| 279 | } else { | 294 | } else { |
| 280 | LOG_INFO(Render_Vulkan, "Device doesn't support packed UBOs"); | 295 | LOG_INFO(Render_Vulkan, "Device doesn't support packed UBOs"); |
| @@ -282,9 +297,11 @@ bool VKDevice::Create() { | |||
| 282 | 297 | ||
| 283 | VkPhysicalDeviceIndexTypeUint8FeaturesEXT index_type_uint8; | 298 | VkPhysicalDeviceIndexTypeUint8FeaturesEXT index_type_uint8; |
| 284 | if (ext_index_type_uint8) { | 299 | if (ext_index_type_uint8) { |
| 285 | index_type_uint8.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT; | 300 | index_type_uint8 = { |
| 286 | index_type_uint8.pNext = nullptr; | 301 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT, |
| 287 | index_type_uint8.indexTypeUint8 = true; | 302 | .pNext = nullptr, |
| 303 | .indexTypeUint8 = true, | ||
| 304 | }; | ||
| 288 | SetNext(next, index_type_uint8); | 305 | SetNext(next, index_type_uint8); |
| 289 | } else { | 306 | } else { |
| 290 | LOG_INFO(Render_Vulkan, "Device doesn't support uint8 indexes"); | 307 | LOG_INFO(Render_Vulkan, "Device doesn't support uint8 indexes"); |
| @@ -292,11 +309,12 @@ bool VKDevice::Create() { | |||
| 292 | 309 | ||
| 293 | VkPhysicalDeviceTransformFeedbackFeaturesEXT transform_feedback; | 310 | VkPhysicalDeviceTransformFeedbackFeaturesEXT transform_feedback; |
| 294 | if (ext_transform_feedback) { | 311 | if (ext_transform_feedback) { |
| 295 | transform_feedback.sType = | 312 | transform_feedback = { |
| 296 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT; | 313 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT, |
| 297 | transform_feedback.pNext = nullptr; | 314 | .pNext = nullptr, |
| 298 | transform_feedback.transformFeedback = true; | 315 | .transformFeedback = true, |
| 299 | transform_feedback.geometryStreams = true; | 316 | .geometryStreams = true, |
| 317 | }; | ||
| 300 | SetNext(next, transform_feedback); | 318 | SetNext(next, transform_feedback); |
| 301 | } else { | 319 | } else { |
| 302 | LOG_INFO(Render_Vulkan, "Device doesn't support transform feedbacks"); | 320 | LOG_INFO(Render_Vulkan, "Device doesn't support transform feedbacks"); |
| @@ -304,10 +322,12 @@ bool VKDevice::Create() { | |||
| 304 | 322 | ||
| 305 | VkPhysicalDeviceCustomBorderColorFeaturesEXT custom_border; | 323 | VkPhysicalDeviceCustomBorderColorFeaturesEXT custom_border; |
| 306 | if (ext_custom_border_color) { | 324 | if (ext_custom_border_color) { |
| 307 | custom_border.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT; | 325 | custom_border = { |
| 308 | custom_border.pNext = nullptr; | 326 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT, |
| 309 | custom_border.customBorderColors = VK_TRUE; | 327 | .pNext = nullptr, |
| 310 | custom_border.customBorderColorWithoutFormat = VK_TRUE; | 328 | .customBorderColors = VK_TRUE, |
| 329 | .customBorderColorWithoutFormat = VK_TRUE, | ||
| 330 | }; | ||
| 311 | SetNext(next, custom_border); | 331 | SetNext(next, custom_border); |
| 312 | } else { | 332 | } else { |
| 313 | LOG_INFO(Render_Vulkan, "Device doesn't support custom border colors"); | 333 | LOG_INFO(Render_Vulkan, "Device doesn't support custom border colors"); |
| @@ -315,9 +335,11 @@ bool VKDevice::Create() { | |||
| 315 | 335 | ||
| 316 | VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state; | 336 | VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamic_state; |
| 317 | if (ext_extended_dynamic_state) { | 337 | if (ext_extended_dynamic_state) { |
| 318 | dynamic_state.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; | 338 | dynamic_state = { |
| 319 | dynamic_state.pNext = nullptr; | 339 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT, |
| 320 | dynamic_state.extendedDynamicState = VK_TRUE; | 340 | .pNext = nullptr, |
| 341 | .extendedDynamicState = VK_TRUE, | ||
| 342 | }; | ||
| 321 | SetNext(next, dynamic_state); | 343 | SetNext(next, dynamic_state); |
| 322 | } else { | 344 | } else { |
| 323 | LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state"); | 345 | LOG_INFO(Render_Vulkan, "Device doesn't support extended dynamic state"); |
| @@ -331,11 +353,13 @@ bool VKDevice::Create() { | |||
| 331 | if (nv_device_diagnostics_config) { | 353 | if (nv_device_diagnostics_config) { |
| 332 | nsight_aftermath_tracker.Initialize(); | 354 | nsight_aftermath_tracker.Initialize(); |
| 333 | 355 | ||
| 334 | diagnostics_nv.sType = VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV; | 356 | diagnostics_nv = { |
| 335 | diagnostics_nv.pNext = &features2; | 357 | .sType = VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV, |
| 336 | diagnostics_nv.flags = VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV | | 358 | .pNext = &features2, |
| 337 | VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV | | 359 | .flags = VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV | |
| 338 | VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV; | 360 | VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV | |
| 361 | VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV, | ||
| 362 | }; | ||
| 339 | first_next = &diagnostics_nv; | 363 | first_next = &diagnostics_nv; |
| 340 | } | 364 | } |
| 341 | 365 | ||
| @@ -704,13 +728,15 @@ void VKDevice::SetupFeatures() { | |||
| 704 | } | 728 | } |
| 705 | 729 | ||
| 706 | void VKDevice::CollectTelemetryParameters() { | 730 | void VKDevice::CollectTelemetryParameters() { |
| 707 | VkPhysicalDeviceDriverPropertiesKHR driver; | 731 | VkPhysicalDeviceDriverPropertiesKHR driver{ |
| 708 | driver.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR; | 732 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR, |
| 709 | driver.pNext = nullptr; | 733 | .pNext = nullptr, |
| 734 | }; | ||
| 710 | 735 | ||
| 711 | VkPhysicalDeviceProperties2KHR properties; | 736 | VkPhysicalDeviceProperties2KHR properties{ |
| 712 | properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; | 737 | .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR, |
| 713 | properties.pNext = &driver; | 738 | .pNext = &driver, |
| 739 | }; | ||
| 714 | physical.GetProperties2KHR(properties); | 740 | physical.GetProperties2KHR(properties); |
| 715 | 741 | ||
| 716 | driver_id = driver.driverID; | 742 | driver_id = driver.driverID; |
| @@ -719,24 +745,26 @@ void VKDevice::CollectTelemetryParameters() { | |||
| 719 | const std::vector extensions = physical.EnumerateDeviceExtensionProperties(); | 745 | const std::vector extensions = physical.EnumerateDeviceExtensionProperties(); |
| 720 | reported_extensions.reserve(std::size(extensions)); | 746 | reported_extensions.reserve(std::size(extensions)); |
| 721 | for (const auto& extension : extensions) { | 747 | for (const auto& extension : extensions) { |
| 722 | reported_extensions.push_back(extension.extensionName); | 748 | reported_extensions.emplace_back(extension.extensionName); |
| 723 | } | 749 | } |
| 724 | } | 750 | } |
| 725 | 751 | ||
| 726 | std::vector<VkDeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() const { | 752 | std::vector<VkDeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() const { |
| 727 | static constexpr float QUEUE_PRIORITY = 1.0f; | 753 | static constexpr float QUEUE_PRIORITY = 1.0f; |
| 728 | 754 | ||
| 729 | std::unordered_set<u32> unique_queue_families = {graphics_family, present_family}; | 755 | std::unordered_set<u32> unique_queue_families{graphics_family, present_family}; |
| 730 | std::vector<VkDeviceQueueCreateInfo> queue_cis; | 756 | std::vector<VkDeviceQueueCreateInfo> queue_cis; |
| 757 | queue_cis.reserve(unique_queue_families.size()); | ||
| 731 | 758 | ||
| 732 | for (const u32 queue_family : unique_queue_families) { | 759 | for (const u32 queue_family : unique_queue_families) { |
| 733 | VkDeviceQueueCreateInfo& ci = queue_cis.emplace_back(); | 760 | queue_cis.push_back({ |
| 734 | ci.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; | 761 | .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, |
| 735 | ci.pNext = nullptr; | 762 | .pNext = nullptr, |
| 736 | ci.flags = 0; | 763 | .flags = 0, |
| 737 | ci.queueFamilyIndex = queue_family; | 764 | .queueFamilyIndex = queue_family, |
| 738 | ci.queueCount = 1; | 765 | .queueCount = 1, |
| 739 | ci.pQueuePriorities = &QUEUE_PRIORITY; | 766 | .pQueuePriorities = &QUEUE_PRIORITY, |
| 767 | }); | ||
| 740 | } | 768 | } |
| 741 | 769 | ||
| 742 | return queue_cis; | 770 | return queue_cis; |
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 | |||
| 343 | size += GetInnerMipmapMemorySize(level, as_host_size, uncompressed); | 343 | size += GetInnerMipmapMemorySize(level, as_host_size, uncompressed); |
| 344 | } | 344 | } |
| 345 | if (is_tiled && is_layered) { | 345 | if (is_tiled && is_layered) { |
| 346 | return Common::AlignBits(size, | 346 | return Common::AlignBits(size, Tegra::Texture::GOB_SIZE_SHIFT + block_height + block_depth); |
| 347 | Tegra::Texture::GetGOBSizeShift() + block_height + block_depth); | ||
| 348 | } | 347 | } |
| 349 | return size; | 348 | return size; |
| 350 | } | 349 | } |
| @@ -418,7 +417,7 @@ std::tuple<u32, u32, u32> SurfaceParams::GetBlockOffsetXYZ(u32 offset) const { | |||
| 418 | const u32 block_size = GetBlockSize(); | 417 | const u32 block_size = GetBlockSize(); |
| 419 | const u32 block_index = offset / block_size; | 418 | const u32 block_index = offset / block_size; |
| 420 | const u32 gob_offset = offset % block_size; | 419 | const u32 gob_offset = offset % block_size; |
| 421 | const u32 gob_index = gob_offset / static_cast<u32>(Tegra::Texture::GetGOBSize()); | 420 | const u32 gob_index = gob_offset / static_cast<u32>(Tegra::Texture::GOB_SIZE); |
| 422 | const u32 x_gob_pixels = 64U / GetBytesPerPixel(); | 421 | const u32 x_gob_pixels = 64U / GetBytesPerPixel(); |
| 423 | const u32 x_block_pixels = x_gob_pixels << block_width; | 422 | const u32 x_block_pixels = x_gob_pixels << block_width; |
| 424 | const u32 y_block_pixels = 8U << block_height; | 423 | 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: | |||
| 204 | static std::size_t AlignLayered(const std::size_t out_size, const u32 block_height, | 204 | static std::size_t AlignLayered(const std::size_t out_size, const u32 block_height, |
| 205 | const u32 block_depth) { | 205 | const u32 block_depth) { |
| 206 | return Common::AlignBits(out_size, | 206 | return Common::AlignBits(out_size, |
| 207 | Tegra::Texture::GetGOBSizeShift() + block_height + block_depth); | 207 | Tegra::Texture::GOB_SIZE_SHIFT + block_height + block_depth); |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | /// Converts a width from a type of surface into another. This helps represent the | 210 | /// 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 @@ | |||
| 6 | #include <cstring> | 6 | #include <cstring> |
| 7 | #include "common/alignment.h" | 7 | #include "common/alignment.h" |
| 8 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| 9 | #include "common/bit_util.h" | ||
| 9 | #include "video_core/gpu.h" | 10 | #include "video_core/gpu.h" |
| 10 | #include "video_core/textures/decoders.h" | 11 | #include "video_core/textures/decoders.h" |
| 11 | #include "video_core/textures/texture.h" | 12 | #include "video_core/textures/texture.h" |
| @@ -37,20 +38,10 @@ struct alignas(64) SwizzleTable { | |||
| 37 | std::array<std::array<u16, M>, N> values{}; | 38 | std::array<std::array<u16, M>, N> values{}; |
| 38 | }; | 39 | }; |
| 39 | 40 | ||
| 40 | constexpr u32 gob_size_x_shift = 6; | 41 | constexpr u32 FAST_SWIZZLE_ALIGN = 16; |
| 41 | constexpr u32 gob_size_y_shift = 3; | ||
| 42 | constexpr u32 gob_size_z_shift = 0; | ||
| 43 | constexpr u32 gob_size_shift = gob_size_x_shift + gob_size_y_shift + gob_size_z_shift; | ||
| 44 | 42 | ||
| 45 | constexpr u32 gob_size_x = 1U << gob_size_x_shift; | 43 | constexpr auto LEGACY_SWIZZLE_TABLE = SwizzleTable<GOB_SIZE_X, GOB_SIZE_X, GOB_SIZE_Z>(); |
| 46 | constexpr u32 gob_size_y = 1U << gob_size_y_shift; | 44 | constexpr auto FAST_SWIZZLE_TABLE = SwizzleTable<GOB_SIZE_Y, 4, FAST_SWIZZLE_ALIGN>(); |
| 47 | constexpr u32 gob_size_z = 1U << gob_size_z_shift; | ||
| 48 | constexpr u32 gob_size = 1U << gob_size_shift; | ||
| 49 | |||
| 50 | constexpr u32 fast_swizzle_align = 16; | ||
| 51 | |||
| 52 | constexpr auto legacy_swizzle_table = SwizzleTable<gob_size_y, gob_size_x, gob_size_z>(); | ||
| 53 | constexpr auto fast_swizzle_table = SwizzleTable<gob_size_y, 4, fast_swizzle_align>(); | ||
| 54 | 45 | ||
| 55 | /** | 46 | /** |
| 56 | * This function manages ALL the GOBs(Group of Bytes) Inside a single block. | 47 | * 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 | |||
| 69 | u32 y_address = z_address; | 60 | u32 y_address = z_address; |
| 70 | u32 pixel_base = layer_z * z + y_start * stride_x; | 61 | u32 pixel_base = layer_z * z + y_start * stride_x; |
| 71 | for (u32 y = y_start; y < y_end; y++) { | 62 | for (u32 y = y_start; y < y_end; y++) { |
| 72 | const auto& table = legacy_swizzle_table[y % gob_size_y]; | 63 | const auto& table = LEGACY_SWIZZLE_TABLE[y % GOB_SIZE_Y]; |
| 73 | for (u32 x = x_start; x < x_end; x++) { | 64 | for (u32 x = x_start; x < x_end; x++) { |
| 74 | const u32 swizzle_offset{y_address + table[x * bytes_per_pixel % gob_size_x]}; | 65 | const u32 swizzle_offset{y_address + table[x * bytes_per_pixel % GOB_SIZE_X]}; |
| 75 | const u32 pixel_index{x * out_bytes_per_pixel + pixel_base}; | 66 | const u32 pixel_index{x * out_bytes_per_pixel + pixel_base}; |
| 76 | data_ptrs[unswizzle] = swizzled_data + swizzle_offset; | 67 | data_ptrs[unswizzle] = swizzled_data + swizzle_offset; |
| 77 | data_ptrs[!unswizzle] = unswizzled_data + pixel_index; | 68 | data_ptrs[!unswizzle] = unswizzled_data + pixel_index; |
| 78 | std::memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel); | 69 | std::memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel); |
| 79 | } | 70 | } |
| 80 | pixel_base += stride_x; | 71 | pixel_base += stride_x; |
| 81 | if ((y + 1) % gob_size_y == 0) | 72 | if ((y + 1) % GOB_SIZE_Y == 0) |
| 82 | y_address += gob_size; | 73 | y_address += GOB_SIZE; |
| 83 | } | 74 | } |
| 84 | z_address += xy_block_size; | 75 | z_address += xy_block_size; |
| 85 | } | 76 | } |
| @@ -104,18 +95,18 @@ void FastProcessBlock(u8* const swizzled_data, u8* const unswizzled_data, const | |||
| 104 | u32 y_address = z_address; | 95 | u32 y_address = z_address; |
| 105 | u32 pixel_base = layer_z * z + y_start * stride_x; | 96 | u32 pixel_base = layer_z * z + y_start * stride_x; |
| 106 | for (u32 y = y_start; y < y_end; y++) { | 97 | for (u32 y = y_start; y < y_end; y++) { |
| 107 | const auto& table = fast_swizzle_table[y % gob_size_y]; | 98 | const auto& table = FAST_SWIZZLE_TABLE[y % GOB_SIZE_Y]; |
| 108 | for (u32 xb = x_startb; xb < x_endb; xb += fast_swizzle_align) { | 99 | for (u32 xb = x_startb; xb < x_endb; xb += FAST_SWIZZLE_ALIGN) { |
| 109 | const u32 swizzle_offset{y_address + table[(xb / fast_swizzle_align) % 4]}; | 100 | const u32 swizzle_offset{y_address + table[(xb / FAST_SWIZZLE_ALIGN) % 4]}; |
| 110 | const u32 out_x = xb * out_bytes_per_pixel / bytes_per_pixel; | 101 | const u32 out_x = xb * out_bytes_per_pixel / bytes_per_pixel; |
| 111 | const u32 pixel_index{out_x + pixel_base}; | 102 | const u32 pixel_index{out_x + pixel_base}; |
| 112 | data_ptrs[unswizzle ? 1 : 0] = swizzled_data + swizzle_offset; | 103 | data_ptrs[unswizzle ? 1 : 0] = swizzled_data + swizzle_offset; |
| 113 | data_ptrs[unswizzle ? 0 : 1] = unswizzled_data + pixel_index; | 104 | data_ptrs[unswizzle ? 0 : 1] = unswizzled_data + pixel_index; |
| 114 | std::memcpy(data_ptrs[0], data_ptrs[1], fast_swizzle_align); | 105 | std::memcpy(data_ptrs[0], data_ptrs[1], FAST_SWIZZLE_ALIGN); |
| 115 | } | 106 | } |
| 116 | pixel_base += stride_x; | 107 | pixel_base += stride_x; |
| 117 | if ((y + 1) % gob_size_y == 0) | 108 | if ((y + 1) % GOB_SIZE_Y == 0) |
| 118 | y_address += gob_size; | 109 | y_address += GOB_SIZE; |
| 119 | } | 110 | } |
| 120 | z_address += xy_block_size; | 111 | z_address += xy_block_size; |
| 121 | } | 112 | } |
| @@ -138,9 +129,9 @@ void SwizzledData(u8* const swizzled_data, u8* const unswizzled_data, const bool | |||
| 138 | auto div_ceil = [](const u32 x, const u32 y) { return ((x + y - 1) / y); }; | 129 | auto div_ceil = [](const u32 x, const u32 y) { return ((x + y - 1) / y); }; |
| 139 | const u32 stride_x = width * out_bytes_per_pixel; | 130 | const u32 stride_x = width * out_bytes_per_pixel; |
| 140 | const u32 layer_z = height * stride_x; | 131 | const u32 layer_z = height * stride_x; |
| 141 | const u32 gob_elements_x = gob_size_x / bytes_per_pixel; | 132 | const u32 gob_elements_x = GOB_SIZE_X / bytes_per_pixel; |
| 142 | constexpr u32 gob_elements_y = gob_size_y; | 133 | constexpr u32 gob_elements_y = GOB_SIZE_Y; |
| 143 | constexpr u32 gob_elements_z = gob_size_z; | 134 | constexpr u32 gob_elements_z = GOB_SIZE_Z; |
| 144 | const u32 block_x_elements = gob_elements_x; | 135 | const u32 block_x_elements = gob_elements_x; |
| 145 | const u32 block_y_elements = gob_elements_y * block_height; | 136 | const u32 block_y_elements = gob_elements_y * block_height; |
| 146 | const u32 block_z_elements = gob_elements_z * block_depth; | 137 | 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 | |||
| 148 | const u32 blocks_on_x = div_ceil(aligned_width, block_x_elements); | 139 | const u32 blocks_on_x = div_ceil(aligned_width, block_x_elements); |
| 149 | const u32 blocks_on_y = div_ceil(height, block_y_elements); | 140 | const u32 blocks_on_y = div_ceil(height, block_y_elements); |
| 150 | const u32 blocks_on_z = div_ceil(depth, block_z_elements); | 141 | const u32 blocks_on_z = div_ceil(depth, block_z_elements); |
| 151 | const u32 xy_block_size = gob_size * block_height; | 142 | const u32 xy_block_size = GOB_SIZE * block_height; |
| 152 | const u32 block_size = xy_block_size * block_depth; | 143 | const u32 block_size = xy_block_size * block_depth; |
| 153 | u32 tile_offset = 0; | 144 | u32 tile_offset = 0; |
| 154 | for (u32 zb = 0; zb < blocks_on_z; zb++) { | 145 | 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, | |||
| 182 | bool unswizzle, u32 block_height, u32 block_depth, u32 width_spacing) { | 173 | bool unswizzle, u32 block_height, u32 block_depth, u32 width_spacing) { |
| 183 | const u32 block_height_size{1U << block_height}; | 174 | const u32 block_height_size{1U << block_height}; |
| 184 | const u32 block_depth_size{1U << block_depth}; | 175 | const u32 block_depth_size{1U << block_depth}; |
| 185 | if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % fast_swizzle_align == 0) { | 176 | if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % FAST_SWIZZLE_ALIGN == 0) { |
| 186 | SwizzledData<true>(swizzled_data, unswizzled_data, unswizzle, width, height, depth, | 177 | SwizzledData<true>(swizzled_data, unswizzled_data, unswizzle, width, height, depth, |
| 187 | bytes_per_pixel, out_bytes_per_pixel, block_height_size, | 178 | bytes_per_pixel, out_bytes_per_pixel, block_height_size, |
| 188 | block_depth_size, width_spacing); | 179 | block_depth_size, width_spacing); |
| @@ -259,25 +250,26 @@ std::vector<u8> UnswizzleTexture(u8* address, u32 tile_size_x, u32 tile_size_y, | |||
| 259 | } | 250 | } |
| 260 | 251 | ||
| 261 | void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width, | 252 | void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width, |
| 262 | u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, | 253 | u32 bytes_per_pixel, u8* swizzled_data, const u8* unswizzled_data, |
| 263 | u32 block_height_bit, u32 offset_x, u32 offset_y) { | 254 | u32 block_height_bit, u32 offset_x, u32 offset_y) { |
| 264 | const u32 block_height = 1U << block_height_bit; | 255 | const u32 block_height = 1U << block_height_bit; |
| 265 | const u32 image_width_in_gobs{(swizzled_width * bytes_per_pixel + (gob_size_x - 1)) / | 256 | const u32 image_width_in_gobs = |
| 266 | gob_size_x}; | 257 | (swizzled_width * bytes_per_pixel + (GOB_SIZE_X - 1)) / GOB_SIZE_X; |
| 267 | for (u32 line = 0; line < subrect_height; ++line) { | 258 | for (u32 line = 0; line < subrect_height; ++line) { |
| 268 | const u32 dst_y = line + offset_y; | 259 | const u32 dst_y = line + offset_y; |
| 269 | const u32 gob_address_y = | 260 | const u32 gob_address_y = |
| 270 | (dst_y / (gob_size_y * block_height)) * gob_size * block_height * image_width_in_gobs + | 261 | (dst_y / (GOB_SIZE_Y * block_height)) * GOB_SIZE * block_height * image_width_in_gobs + |
| 271 | ((dst_y % (gob_size_y * block_height)) / gob_size_y) * gob_size; | 262 | ((dst_y % (GOB_SIZE_Y * block_height)) / GOB_SIZE_Y) * GOB_SIZE; |
| 272 | const auto& table = legacy_swizzle_table[dst_y % gob_size_y]; | 263 | const auto& table = LEGACY_SWIZZLE_TABLE[dst_y % GOB_SIZE_Y]; |
| 273 | for (u32 x = 0; x < subrect_width; ++x) { | 264 | for (u32 x = 0; x < subrect_width; ++x) { |
| 274 | const u32 dst_x = x + offset_x; | 265 | const u32 dst_x = x + offset_x; |
| 275 | const u32 gob_address = | 266 | const u32 gob_address = |
| 276 | gob_address_y + (dst_x * bytes_per_pixel / gob_size_x) * gob_size * block_height; | 267 | gob_address_y + (dst_x * bytes_per_pixel / GOB_SIZE_X) * GOB_SIZE * block_height; |
| 277 | const u32 swizzled_offset = gob_address + table[(dst_x * bytes_per_pixel) % gob_size_x]; | 268 | const u32 swizzled_offset = gob_address + table[(dst_x * bytes_per_pixel) % GOB_SIZE_X]; |
| 278 | u8* source_line = unswizzled_data + line * source_pitch + x * bytes_per_pixel; | 269 | const u32 unswizzled_offset = line * source_pitch + x * bytes_per_pixel; |
| 279 | u8* dest_addr = swizzled_data + swizzled_offset; | ||
| 280 | 270 | ||
| 271 | const u8* const source_line = unswizzled_data + unswizzled_offset; | ||
| 272 | u8* const dest_addr = swizzled_data + swizzled_offset; | ||
| 281 | std::memcpy(dest_addr, source_line, bytes_per_pixel); | 273 | std::memcpy(dest_addr, source_line, bytes_per_pixel); |
| 282 | } | 274 | } |
| 283 | } | 275 | } |
| @@ -289,14 +281,15 @@ void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 | |||
| 289 | const u32 block_height = 1U << block_height_bit; | 281 | const u32 block_height = 1U << block_height_bit; |
| 290 | for (u32 line = 0; line < subrect_height; ++line) { | 282 | for (u32 line = 0; line < subrect_height; ++line) { |
| 291 | const u32 y2 = line + offset_y; | 283 | const u32 y2 = line + offset_y; |
| 292 | const u32 gob_address_y = (y2 / (gob_size_y * block_height)) * gob_size * block_height + | 284 | const u32 gob_address_y = (y2 / (GOB_SIZE_Y * block_height)) * GOB_SIZE * block_height + |
| 293 | ((y2 % (gob_size_y * block_height)) / gob_size_y) * gob_size; | 285 | ((y2 % (GOB_SIZE_Y * block_height)) / GOB_SIZE_Y) * GOB_SIZE; |
| 294 | const auto& table = legacy_swizzle_table[y2 % gob_size_y]; | 286 | const auto& table = LEGACY_SWIZZLE_TABLE[y2 % GOB_SIZE_Y]; |
| 295 | for (u32 x = 0; x < subrect_width; ++x) { | 287 | for (u32 x = 0; x < subrect_width; ++x) { |
| 296 | const u32 x2 = (x + offset_x) * bytes_per_pixel; | 288 | const u32 x2 = (x + offset_x) * bytes_per_pixel; |
| 297 | const u32 gob_address = gob_address_y + (x2 / gob_size_x) * gob_size * block_height; | 289 | const u32 gob_address = gob_address_y + (x2 / GOB_SIZE_X) * GOB_SIZE * block_height; |
| 298 | const u32 swizzled_offset = gob_address + table[x2 % gob_size_x]; | 290 | const u32 swizzled_offset = gob_address + table[x2 % GOB_SIZE_X]; |
| 299 | u8* dest_line = unswizzled_data + line * dest_pitch + x * bytes_per_pixel; | 291 | const u32 unswizzled_offset = line * dest_pitch + x * bytes_per_pixel; |
| 292 | u8* dest_line = unswizzled_data + unswizzled_offset; | ||
| 300 | u8* source_addr = swizzled_data + swizzled_offset; | 293 | u8* source_addr = swizzled_data + swizzled_offset; |
| 301 | 294 | ||
| 302 | std::memcpy(dest_line, source_addr, bytes_per_pixel); | 295 | 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 | |||
| 304 | } | 297 | } |
| 305 | } | 298 | } |
| 306 | 299 | ||
| 300 | void SwizzleSliceToVoxel(u32 line_length_in, u32 line_count, u32 pitch, u32 width, u32 height, | ||
| 301 | u32 bytes_per_pixel, u32 block_height, u32 block_depth, u32 origin_x, | ||
| 302 | u32 origin_y, u8* output, const u8* input) { | ||
| 303 | UNIMPLEMENTED_IF(origin_x > 0); | ||
| 304 | UNIMPLEMENTED_IF(origin_y > 0); | ||
| 305 | |||
| 306 | const u32 stride = width * bytes_per_pixel; | ||
| 307 | const u32 gobs_in_x = (stride + GOB_SIZE_X - 1) / GOB_SIZE_X; | ||
| 308 | const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height + block_depth); | ||
| 309 | |||
| 310 | const u32 block_height_mask = (1U << block_height) - 1; | ||
| 311 | const u32 x_shift = Common::CountTrailingZeroes32(GOB_SIZE << (block_height + block_depth)); | ||
| 312 | |||
| 313 | for (u32 line = 0; line < line_count; ++line) { | ||
| 314 | const auto& table = LEGACY_SWIZZLE_TABLE[line % GOB_SIZE_Y]; | ||
| 315 | const u32 block_y = line / GOB_SIZE_Y; | ||
| 316 | const u32 dst_offset_y = | ||
| 317 | (block_y >> block_height) * block_size + (block_y & block_height_mask) * GOB_SIZE; | ||
| 318 | for (u32 x = 0; x < line_length_in; ++x) { | ||
| 319 | const u32 dst_offset = | ||
| 320 | ((x / GOB_SIZE_X) << x_shift) + dst_offset_y + table[x % GOB_SIZE_X]; | ||
| 321 | const u32 src_offset = x * bytes_per_pixel + line * pitch; | ||
| 322 | std::memcpy(output + dst_offset, input + src_offset, bytes_per_pixel); | ||
| 323 | } | ||
| 324 | } | ||
| 325 | } | ||
| 326 | |||
| 307 | void SwizzleKepler(const u32 width, const u32 height, const u32 dst_x, const u32 dst_y, | 327 | void SwizzleKepler(const u32 width, const u32 height, const u32 dst_x, const u32 dst_y, |
| 308 | const u32 block_height_bit, const std::size_t copy_size, const u8* source_data, | 328 | const u32 block_height_bit, const std::size_t copy_size, const u8* source_data, |
| 309 | u8* swizzle_data) { | 329 | u8* swizzle_data) { |
| 310 | const u32 block_height = 1U << block_height_bit; | 330 | const u32 block_height = 1U << block_height_bit; |
| 311 | const u32 image_width_in_gobs{(width + gob_size_x - 1) / gob_size_x}; | 331 | const u32 image_width_in_gobs{(width + GOB_SIZE_X - 1) / GOB_SIZE_X}; |
| 312 | std::size_t count = 0; | 332 | std::size_t count = 0; |
| 313 | for (std::size_t y = dst_y; y < height && count < copy_size; ++y) { | 333 | for (std::size_t y = dst_y; y < height && count < copy_size; ++y) { |
| 314 | const std::size_t gob_address_y = | 334 | const std::size_t gob_address_y = |
| 315 | (y / (gob_size_y * block_height)) * gob_size * block_height * image_width_in_gobs + | 335 | (y / (GOB_SIZE_Y * block_height)) * GOB_SIZE * block_height * image_width_in_gobs + |
| 316 | ((y % (gob_size_y * block_height)) / gob_size_y) * gob_size; | 336 | ((y % (GOB_SIZE_Y * block_height)) / GOB_SIZE_Y) * GOB_SIZE; |
| 317 | const auto& table = legacy_swizzle_table[y % gob_size_y]; | 337 | const auto& table = LEGACY_SWIZZLE_TABLE[y % GOB_SIZE_Y]; |
| 318 | for (std::size_t x = dst_x; x < width && count < copy_size; ++x) { | 338 | for (std::size_t x = dst_x; x < width && count < copy_size; ++x) { |
| 319 | const std::size_t gob_address = | 339 | const std::size_t gob_address = |
| 320 | gob_address_y + (x / gob_size_x) * gob_size * block_height; | 340 | gob_address_y + (x / GOB_SIZE_X) * GOB_SIZE * block_height; |
| 321 | const std::size_t swizzled_offset = gob_address + table[x % gob_size_x]; | 341 | const std::size_t swizzled_offset = gob_address + table[x % GOB_SIZE_X]; |
| 322 | const u8* source_line = source_data + count; | 342 | const u8* source_line = source_data + count; |
| 323 | u8* dest_addr = swizzle_data + swizzled_offset; | 343 | u8* dest_addr = swizzle_data + swizzled_offset; |
| 324 | count++; | 344 | count++; |
| @@ -373,9 +393,9 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat | |||
| 373 | std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth, | 393 | std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth, |
| 374 | u32 block_height, u32 block_depth) { | 394 | u32 block_height, u32 block_depth) { |
| 375 | if (tiled) { | 395 | if (tiled) { |
| 376 | const u32 aligned_width = Common::AlignBits(width * bytes_per_pixel, gob_size_x_shift); | 396 | const u32 aligned_width = Common::AlignBits(width * bytes_per_pixel, GOB_SIZE_X_SHIFT); |
| 377 | const u32 aligned_height = Common::AlignBits(height, gob_size_y_shift + block_height); | 397 | const u32 aligned_height = Common::AlignBits(height, GOB_SIZE_Y_SHIFT + block_height); |
| 378 | const u32 aligned_depth = Common::AlignBits(depth, gob_size_z_shift + block_depth); | 398 | const u32 aligned_depth = Common::AlignBits(depth, GOB_SIZE_Z_SHIFT + block_depth); |
| 379 | return aligned_width * aligned_height * aligned_depth; | 399 | return aligned_width * aligned_height * aligned_depth; |
| 380 | } else { | 400 | } else { |
| 381 | return width * height * depth * bytes_per_pixel; | 401 | 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, | |||
| 386 | u32 bytes_per_pixel) { | 406 | u32 bytes_per_pixel) { |
| 387 | auto div_ceil = [](const u32 x, const u32 y) { return ((x + y - 1) / y); }; | 407 | auto div_ceil = [](const u32 x, const u32 y) { return ((x + y - 1) / y); }; |
| 388 | const u32 gobs_in_block = 1 << block_height; | 408 | const u32 gobs_in_block = 1 << block_height; |
| 389 | const u32 y_blocks = gob_size_y << block_height; | 409 | const u32 y_blocks = GOB_SIZE_Y << block_height; |
| 390 | const u32 x_per_gob = gob_size_x / bytes_per_pixel; | 410 | const u32 x_per_gob = GOB_SIZE_X / bytes_per_pixel; |
| 391 | const u32 x_blocks = div_ceil(width, x_per_gob); | 411 | const u32 x_blocks = div_ceil(width, x_per_gob); |
| 392 | const u32 block_size = gob_size * gobs_in_block; | 412 | const u32 block_size = GOB_SIZE * gobs_in_block; |
| 393 | const u32 stride = block_size * x_blocks; | 413 | const u32 stride = block_size * x_blocks; |
| 394 | const u32 base = (dst_y / y_blocks) * stride + (dst_x / x_per_gob) * block_size; | 414 | const u32 base = (dst_y / y_blocks) * stride + (dst_x / x_per_gob) * block_size; |
| 395 | const u32 relative_y = dst_y % y_blocks; | 415 | const u32 relative_y = dst_y % y_blocks; |
| 396 | return base + (relative_y / gob_size_y) * gob_size; | 416 | return base + (relative_y / GOB_SIZE_Y) * GOB_SIZE; |
| 397 | } | 417 | } |
| 398 | 418 | ||
| 399 | } // namespace Tegra::Texture | 419 | } // 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 @@ | |||
| 10 | 10 | ||
| 11 | namespace Tegra::Texture { | 11 | namespace Tegra::Texture { |
| 12 | 12 | ||
| 13 | // GOBSize constant. Calculated by 64 bytes in x multiplied by 8 y coords, represents | 13 | constexpr u32 GOB_SIZE_X = 64; |
| 14 | // an small rect of (64/bytes_per_pixel)X8. | 14 | constexpr u32 GOB_SIZE_Y = 8; |
| 15 | inline std::size_t GetGOBSize() { | 15 | constexpr u32 GOB_SIZE_Z = 1; |
| 16 | return 512; | 16 | constexpr u32 GOB_SIZE = GOB_SIZE_X * GOB_SIZE_Y * GOB_SIZE_Z; |
| 17 | } | ||
| 18 | 17 | ||
| 19 | inline std::size_t GetGOBSizeShift() { | 18 | constexpr std::size_t GOB_SIZE_X_SHIFT = 6; |
| 20 | return 9; | 19 | constexpr std::size_t GOB_SIZE_Y_SHIFT = 3; |
| 21 | } | 20 | constexpr std::size_t GOB_SIZE_Z_SHIFT = 0; |
| 21 | constexpr std::size_t GOB_SIZE_SHIFT = GOB_SIZE_X_SHIFT + GOB_SIZE_Y_SHIFT + GOB_SIZE_Z_SHIFT; | ||
| 22 | 22 | ||
| 23 | /// Unswizzles a swizzled texture without changing its format. | 23 | /// Unswizzles a swizzled texture without changing its format. |
| 24 | void UnswizzleTexture(u8* unswizzled_data, u8* address, u32 tile_size_x, u32 tile_size_y, | 24 | 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 | |||
| 48 | 48 | ||
| 49 | /// Copies an untiled subrectangle into a tiled surface. | 49 | /// Copies an untiled subrectangle into a tiled surface. |
| 50 | void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width, | 50 | void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width, |
| 51 | u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, u32 block_height, | 51 | u32 bytes_per_pixel, u8* swizzled_data, const u8* unswizzled_data, |
| 52 | u32 offset_x, u32 offset_y); | 52 | u32 block_height_bit, u32 offset_x, u32 offset_y); |
| 53 | 53 | ||
| 54 | /// Copies a tiled subrectangle into a linear surface. | 54 | /// Copies a tiled subrectangle into a linear surface. |
| 55 | void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 swizzled_width, | 55 | void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 swizzled_width, |
| 56 | u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, u32 block_height, | 56 | u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, u32 block_height, |
| 57 | u32 offset_x, u32 offset_y); | 57 | u32 offset_x, u32 offset_y); |
| 58 | 58 | ||
| 59 | /// @brief Swizzles a 2D array of pixels into a 3D texture | ||
| 60 | /// @param line_length_in Number of pixels per line | ||
| 61 | /// @param line_count Number of lines | ||
| 62 | /// @param pitch Number of bytes per line | ||
| 63 | /// @param width Width of the swizzled texture | ||
| 64 | /// @param height Height of the swizzled texture | ||
| 65 | /// @param bytes_per_pixel Number of bytes used per pixel | ||
| 66 | /// @param block_height Block height shift | ||
| 67 | /// @param block_depth Block depth shift | ||
| 68 | /// @param origin_x Column offset in pixels of the swizzled texture | ||
| 69 | /// @param origin_y Row offset in pixels of the swizzled texture | ||
| 70 | /// @param output Pointer to the pixels of the swizzled texture | ||
| 71 | /// @param input Pointer to the 2D array of pixels used as input | ||
| 72 | /// @pre input and output points to an array large enough to hold the number of bytes used | ||
| 73 | void SwizzleSliceToVoxel(u32 line_length_in, u32 line_count, u32 pitch, u32 width, u32 height, | ||
| 74 | u32 bytes_per_pixel, u32 block_height, u32 block_depth, u32 origin_x, | ||
| 75 | u32 origin_y, u8* output, const u8* input); | ||
| 76 | |||
| 59 | void SwizzleKepler(u32 width, u32 height, u32 dst_x, u32 dst_y, u32 block_height, | 77 | void SwizzleKepler(u32 width, u32 height, u32 dst_x, u32 dst_y, u32 block_height, |
| 60 | std::size_t copy_size, const u8* source_data, u8* swizzle_data); | 78 | std::size_t copy_size, const u8* source_data, u8* swizzle_data); |
| 61 | 79 | ||
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index ff7d9c1fa..a862b2610 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -30,6 +30,12 @@ add_executable(yuzu | |||
| 30 | configuration/configure_audio.cpp | 30 | configuration/configure_audio.cpp |
| 31 | configuration/configure_audio.h | 31 | configuration/configure_audio.h |
| 32 | configuration/configure_audio.ui | 32 | configuration/configure_audio.ui |
| 33 | configuration/configure_cpu.cpp | ||
| 34 | configuration/configure_cpu.h | ||
| 35 | configuration/configure_cpu.ui | ||
| 36 | configuration/configure_cpu_debug.cpp | ||
| 37 | configuration/configure_cpu_debug.h | ||
| 38 | configuration/configure_cpu_debug.ui | ||
| 33 | configuration/configure_debug.cpp | 39 | configuration/configure_debug.cpp |
| 34 | configuration/configure_debug.h | 40 | configuration/configure_debug.h |
| 35 | configuration/configure_debug.ui | 41 | configuration/configure_debug.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() { | |||
| 505 | ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool(); | 505 | ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool(); |
| 506 | Settings::values.gamecard_path = | 506 | Settings::values.gamecard_path = |
| 507 | ReadSetting(QStringLiteral("gamecard_path"), QStringLiteral("")).toString().toStdString(); | 507 | ReadSetting(QStringLiteral("gamecard_path"), QStringLiteral("")).toString().toStdString(); |
| 508 | Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>( | ||
| 509 | ReadSetting(QStringLiteral("nand_total_size"), | ||
| 510 | QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDTotalSize::S29_1GB))) | ||
| 511 | .toULongLong()); | ||
| 512 | Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>( | ||
| 513 | ReadSetting(QStringLiteral("nand_user_size"), | ||
| 514 | QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDUserSize::S26GB))) | ||
| 515 | .toULongLong()); | ||
| 516 | Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>( | ||
| 517 | ReadSetting(QStringLiteral("nand_system_size"), | ||
| 518 | QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDSystemSize::S2_5GB))) | ||
| 519 | .toULongLong()); | ||
| 520 | Settings::values.sdmc_size = static_cast<Settings::SDMCSize>( | ||
| 521 | ReadSetting(QStringLiteral("sdmc_size"), | ||
| 522 | QVariant::fromValue<u64>(static_cast<u64>(Settings::SDMCSize::S16GB))) | ||
| 523 | .toULongLong()); | ||
| 524 | 508 | ||
| 525 | qt_config->endGroup(); | 509 | qt_config->endGroup(); |
| 526 | } | 510 | } |
| @@ -540,8 +524,6 @@ void Config::ReadDebuggingValues() { | |||
| 540 | Settings::values.reporting_services = | 524 | Settings::values.reporting_services = |
| 541 | ReadSetting(QStringLiteral("reporting_services"), false).toBool(); | 525 | ReadSetting(QStringLiteral("reporting_services"), false).toBool(); |
| 542 | Settings::values.quest_flag = ReadSetting(QStringLiteral("quest_flag"), false).toBool(); | 526 | Settings::values.quest_flag = ReadSetting(QStringLiteral("quest_flag"), false).toBool(); |
| 543 | Settings::values.disable_cpu_opt = | ||
| 544 | ReadSetting(QStringLiteral("disable_cpu_opt"), false).toBool(); | ||
| 545 | Settings::values.disable_macro_jit = | 527 | Settings::values.disable_macro_jit = |
| 546 | ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool(); | 528 | ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool(); |
| 547 | 529 | ||
| @@ -633,6 +615,34 @@ void Config::ReadPathValues() { | |||
| 633 | qt_config->endGroup(); | 615 | qt_config->endGroup(); |
| 634 | } | 616 | } |
| 635 | 617 | ||
| 618 | void Config::ReadCpuValues() { | ||
| 619 | qt_config->beginGroup(QStringLiteral("Cpu")); | ||
| 620 | |||
| 621 | if (global) { | ||
| 622 | Settings::values.cpu_accuracy = static_cast<Settings::CPUAccuracy>( | ||
| 623 | ReadSetting(QStringLiteral("cpu_accuracy"), 0).toInt()); | ||
| 624 | |||
| 625 | Settings::values.cpuopt_page_tables = | ||
| 626 | ReadSetting(QStringLiteral("cpuopt_page_tables"), true).toBool(); | ||
| 627 | Settings::values.cpuopt_block_linking = | ||
| 628 | ReadSetting(QStringLiteral("cpuopt_block_linking"), true).toBool(); | ||
| 629 | Settings::values.cpuopt_return_stack_buffer = | ||
| 630 | ReadSetting(QStringLiteral("cpuopt_return_stack_buffer"), true).toBool(); | ||
| 631 | Settings::values.cpuopt_fast_dispatcher = | ||
| 632 | ReadSetting(QStringLiteral("cpuopt_fast_dispatcher"), true).toBool(); | ||
| 633 | Settings::values.cpuopt_context_elimination = | ||
| 634 | ReadSetting(QStringLiteral("cpuopt_context_elimination"), true).toBool(); | ||
| 635 | Settings::values.cpuopt_const_prop = | ||
| 636 | ReadSetting(QStringLiteral("cpuopt_const_prop"), true).toBool(); | ||
| 637 | Settings::values.cpuopt_misc_ir = | ||
| 638 | ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool(); | ||
| 639 | Settings::values.cpuopt_reduce_misalign_checks = | ||
| 640 | ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool(); | ||
| 641 | } | ||
| 642 | |||
| 643 | qt_config->endGroup(); | ||
| 644 | } | ||
| 645 | |||
| 636 | void Config::ReadRendererValues() { | 646 | void Config::ReadRendererValues() { |
| 637 | qt_config->beginGroup(QStringLiteral("Renderer")); | 647 | qt_config->beginGroup(QStringLiteral("Renderer")); |
| 638 | 648 | ||
| @@ -829,6 +839,7 @@ void Config::ReadValues() { | |||
| 829 | ReadMiscellaneousValues(); | 839 | ReadMiscellaneousValues(); |
| 830 | } | 840 | } |
| 831 | ReadCoreValues(); | 841 | ReadCoreValues(); |
| 842 | ReadCpuValues(); | ||
| 832 | ReadRendererValues(); | 843 | ReadRendererValues(); |
| 833 | ReadAudioValues(); | 844 | ReadAudioValues(); |
| 834 | ReadSystemValues(); | 845 | ReadSystemValues(); |
| @@ -929,6 +940,7 @@ void Config::SaveValues() { | |||
| 929 | SaveMiscellaneousValues(); | 940 | SaveMiscellaneousValues(); |
| 930 | } | 941 | } |
| 931 | SaveCoreValues(); | 942 | SaveCoreValues(); |
| 943 | SaveCpuValues(); | ||
| 932 | SaveRendererValues(); | 944 | SaveRendererValues(); |
| 933 | SaveAudioValues(); | 945 | SaveAudioValues(); |
| 934 | SaveSystemValues(); | 946 | SaveSystemValues(); |
| @@ -1006,18 +1018,7 @@ void Config::SaveDataStorageValues() { | |||
| 1006 | false); | 1018 | false); |
| 1007 | WriteSetting(QStringLiteral("gamecard_path"), | 1019 | WriteSetting(QStringLiteral("gamecard_path"), |
| 1008 | QString::fromStdString(Settings::values.gamecard_path), QStringLiteral("")); | 1020 | QString::fromStdString(Settings::values.gamecard_path), QStringLiteral("")); |
| 1009 | WriteSetting(QStringLiteral("nand_total_size"), | 1021 | |
| 1010 | QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_total_size)), | ||
| 1011 | QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDTotalSize::S29_1GB))); | ||
| 1012 | WriteSetting(QStringLiteral("nand_user_size"), | ||
| 1013 | QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_user_size)), | ||
| 1014 | QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDUserSize::S26GB))); | ||
| 1015 | WriteSetting(QStringLiteral("nand_system_size"), | ||
| 1016 | QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_system_size)), | ||
| 1017 | QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDSystemSize::S2_5GB))); | ||
| 1018 | WriteSetting(QStringLiteral("sdmc_size"), | ||
| 1019 | QVariant::fromValue<u64>(static_cast<u64>(Settings::values.sdmc_size)), | ||
| 1020 | QVariant::fromValue<u64>(static_cast<u64>(Settings::SDMCSize::S16GB))); | ||
| 1021 | qt_config->endGroup(); | 1022 | qt_config->endGroup(); |
| 1022 | } | 1023 | } |
| 1023 | 1024 | ||
| @@ -1033,7 +1034,6 @@ void Config::SaveDebuggingValues() { | |||
| 1033 | WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false); | 1034 | WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false); |
| 1034 | WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false); | 1035 | WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false); |
| 1035 | WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false); | 1036 | WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false); |
| 1036 | WriteSetting(QStringLiteral("disable_cpu_opt"), Settings::values.disable_cpu_opt, false); | ||
| 1037 | WriteSetting(QStringLiteral("disable_macro_jit"), Settings::values.disable_macro_jit, false); | 1037 | WriteSetting(QStringLiteral("disable_macro_jit"), Settings::values.disable_macro_jit, false); |
| 1038 | 1038 | ||
| 1039 | qt_config->endGroup(); | 1039 | qt_config->endGroup(); |
| @@ -1097,6 +1097,32 @@ void Config::SavePathValues() { | |||
| 1097 | qt_config->endGroup(); | 1097 | qt_config->endGroup(); |
| 1098 | } | 1098 | } |
| 1099 | 1099 | ||
| 1100 | void Config::SaveCpuValues() { | ||
| 1101 | qt_config->beginGroup(QStringLiteral("Cpu")); | ||
| 1102 | |||
| 1103 | if (global) { | ||
| 1104 | WriteSetting(QStringLiteral("cpu_accuracy"), | ||
| 1105 | static_cast<int>(Settings::values.cpu_accuracy), 0); | ||
| 1106 | |||
| 1107 | WriteSetting(QStringLiteral("cpuopt_page_tables"), Settings::values.cpuopt_page_tables, | ||
| 1108 | true); | ||
| 1109 | WriteSetting(QStringLiteral("cpuopt_block_linking"), Settings::values.cpuopt_block_linking, | ||
| 1110 | true); | ||
| 1111 | WriteSetting(QStringLiteral("cpuopt_return_stack_buffer"), | ||
| 1112 | Settings::values.cpuopt_return_stack_buffer, true); | ||
| 1113 | WriteSetting(QStringLiteral("cpuopt_fast_dispatcher"), | ||
| 1114 | Settings::values.cpuopt_fast_dispatcher, true); | ||
| 1115 | WriteSetting(QStringLiteral("cpuopt_context_elimination"), | ||
| 1116 | Settings::values.cpuopt_context_elimination, true); | ||
| 1117 | WriteSetting(QStringLiteral("cpuopt_const_prop"), Settings::values.cpuopt_const_prop, true); | ||
| 1118 | WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true); | ||
| 1119 | WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), | ||
| 1120 | Settings::values.cpuopt_reduce_misalign_checks, true); | ||
| 1121 | } | ||
| 1122 | |||
| 1123 | qt_config->endGroup(); | ||
| 1124 | } | ||
| 1125 | |||
| 1100 | void Config::SaveRendererValues() { | 1126 | void Config::SaveRendererValues() { |
| 1101 | qt_config->beginGroup(QStringLiteral("Renderer")); | 1127 | qt_config->beginGroup(QStringLiteral("Renderer")); |
| 1102 | 1128 | ||
| @@ -1342,11 +1368,13 @@ void Config::WriteSettingGlobal(const QString& name, const QVariant& value, bool | |||
| 1342 | 1368 | ||
| 1343 | void Config::Reload() { | 1369 | void Config::Reload() { |
| 1344 | ReadValues(); | 1370 | ReadValues(); |
| 1371 | Settings::Sanitize(); | ||
| 1345 | // To apply default value changes | 1372 | // To apply default value changes |
| 1346 | SaveValues(); | 1373 | SaveValues(); |
| 1347 | Settings::Apply(); | 1374 | Settings::Apply(); |
| 1348 | } | 1375 | } |
| 1349 | 1376 | ||
| 1350 | void Config::Save() { | 1377 | void Config::Save() { |
| 1378 | Settings::Sanitize(); | ||
| 1351 | SaveValues(); | 1379 | SaveValues(); |
| 1352 | } | 1380 | } |
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: | |||
| 49 | void ReadDisabledAddOnValues(); | 49 | void ReadDisabledAddOnValues(); |
| 50 | void ReadMiscellaneousValues(); | 50 | void ReadMiscellaneousValues(); |
| 51 | void ReadPathValues(); | 51 | void ReadPathValues(); |
| 52 | void ReadCpuValues(); | ||
| 52 | void ReadRendererValues(); | 53 | void ReadRendererValues(); |
| 53 | void ReadShortcutValues(); | 54 | void ReadShortcutValues(); |
| 54 | void ReadSystemValues(); | 55 | void ReadSystemValues(); |
| @@ -73,6 +74,7 @@ private: | |||
| 73 | void SaveDisabledAddOnValues(); | 74 | void SaveDisabledAddOnValues(); |
| 74 | void SaveMiscellaneousValues(); | 75 | void SaveMiscellaneousValues(); |
| 75 | void SavePathValues(); | 76 | void SavePathValues(); |
| 77 | void SaveCpuValues(); | ||
| 76 | void SaveRendererValues(); | 78 | void SaveRendererValues(); |
| 77 | void SaveShortcutValues(); | 79 | void SaveShortcutValues(); |
| 78 | void SaveSystemValues(); | 80 | 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 @@ | |||
| 78 | <string>Hotkeys</string> | 78 | <string>Hotkeys</string> |
| 79 | </attribute> | 79 | </attribute> |
| 80 | </widget> | 80 | </widget> |
| 81 | <widget class="ConfigureCpu" name="cpuTab"> | ||
| 82 | <attribute name="title"> | ||
| 83 | <string>CPU</string> | ||
| 84 | </attribute> | ||
| 85 | </widget> | ||
| 86 | <widget class="ConfigureCpuDebug" name="cpuDebugTab"> | ||
| 87 | <attribute name="title"> | ||
| 88 | <string>Debug</string> | ||
| 89 | </attribute> | ||
| 90 | </widget> | ||
| 81 | <widget class="ConfigureGraphics" name="graphicsTab"> | 91 | <widget class="ConfigureGraphics" name="graphicsTab"> |
| 82 | <attribute name="title"> | 92 | <attribute name="title"> |
| 83 | <string>Graphics</string> | 93 | <string>Graphics</string> |
| @@ -159,6 +169,18 @@ | |||
| 159 | <container>1</container> | 169 | <container>1</container> |
| 160 | </customwidget> | 170 | </customwidget> |
| 161 | <customwidget> | 171 | <customwidget> |
| 172 | <class>ConfigureCpu</class> | ||
| 173 | <extends>QWidget</extends> | ||
| 174 | <header>configuration/configure_cpu.h</header> | ||
| 175 | <container>1</container> | ||
| 176 | </customwidget> | ||
| 177 | <customwidget> | ||
| 178 | <class>ConfigureCpuDebug</class> | ||
| 179 | <extends>QWidget</extends> | ||
| 180 | <header>configuration/configure_cpu_debug.h</header> | ||
| 181 | <container>1</container> | ||
| 182 | </customwidget> | ||
| 183 | <customwidget> | ||
| 162 | <class>ConfigureGraphics</class> | 184 | <class>ConfigureGraphics</class> |
| 163 | <extends>QWidget</extends> | 185 | <extends>QWidget</extends> |
| 164 | <header>configuration/configure_graphics.h</header> | 186 | <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 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <QComboBox> | ||
| 6 | #include <QMessageBox> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "common/logging/log.h" | ||
| 10 | #include "core/core.h" | ||
| 11 | #include "core/settings.h" | ||
| 12 | #include "ui_configure_cpu.h" | ||
| 13 | #include "yuzu/configuration/configure_cpu.h" | ||
| 14 | |||
| 15 | ConfigureCpu::ConfigureCpu(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureCpu) { | ||
| 16 | ui->setupUi(this); | ||
| 17 | |||
| 18 | SetConfiguration(); | ||
| 19 | |||
| 20 | connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this, | ||
| 21 | &ConfigureCpu::AccuracyUpdated); | ||
| 22 | } | ||
| 23 | |||
| 24 | ConfigureCpu::~ConfigureCpu() = default; | ||
| 25 | |||
| 26 | void ConfigureCpu::SetConfiguration() { | ||
| 27 | const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); | ||
| 28 | |||
| 29 | ui->accuracy->setEnabled(runtime_lock); | ||
| 30 | ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy)); | ||
| 31 | } | ||
| 32 | |||
| 33 | void ConfigureCpu::AccuracyUpdated(int index) { | ||
| 34 | if (static_cast<Settings::CPUAccuracy>(index) == Settings::CPUAccuracy::DebugMode) { | ||
| 35 | const auto result = QMessageBox::warning(this, tr("Setting CPU to Debug Mode"), | ||
| 36 | tr("CPU Debug Mode is only intended for developer " | ||
| 37 | "use. Are you sure you want to enable this?"), | ||
| 38 | QMessageBox::Yes | QMessageBox::No); | ||
| 39 | if (result == QMessageBox::No) { | ||
| 40 | ui->accuracy->setCurrentIndex(static_cast<int>(Settings::CPUAccuracy::Accurate)); | ||
| 41 | return; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | void ConfigureCpu::ApplyConfiguration() { | ||
| 47 | Settings::values.cpu_accuracy = | ||
| 48 | static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex()); | ||
| 49 | } | ||
| 50 | |||
| 51 | void ConfigureCpu::changeEvent(QEvent* event) { | ||
| 52 | if (event->type() == QEvent::LanguageChange) { | ||
| 53 | RetranslateUI(); | ||
| 54 | } | ||
| 55 | |||
| 56 | QWidget::changeEvent(event); | ||
| 57 | } | ||
| 58 | |||
| 59 | void ConfigureCpu::RetranslateUI() { | ||
| 60 | ui->retranslateUi(this); | ||
| 61 | } | ||
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 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <QWidget> | ||
| 9 | #include "core/settings.h" | ||
| 10 | |||
| 11 | namespace Ui { | ||
| 12 | class ConfigureCpu; | ||
| 13 | } | ||
| 14 | |||
| 15 | class ConfigureCpu : public QWidget { | ||
| 16 | Q_OBJECT | ||
| 17 | |||
| 18 | public: | ||
| 19 | explicit ConfigureCpu(QWidget* parent = nullptr); | ||
| 20 | ~ConfigureCpu() override; | ||
| 21 | |||
| 22 | void ApplyConfiguration(); | ||
| 23 | |||
| 24 | private: | ||
| 25 | void changeEvent(QEvent* event) override; | ||
| 26 | void RetranslateUI(); | ||
| 27 | |||
| 28 | void AccuracyUpdated(int index); | ||
| 29 | |||
| 30 | void SetConfiguration(); | ||
| 31 | |||
| 32 | std::unique_ptr<Ui::ConfigureCpu> ui; | ||
| 33 | }; | ||
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 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <ui version="4.0"> | ||
| 3 | <class>ConfigureCpu</class> | ||
| 4 | <widget class="QWidget" name="ConfigureCpu"> | ||
| 5 | <property name="geometry"> | ||
| 6 | <rect> | ||
| 7 | <x>0</x> | ||
| 8 | <y>0</y> | ||
| 9 | <width>400</width> | ||
| 10 | <height>321</height> | ||
| 11 | </rect> | ||
| 12 | </property> | ||
| 13 | <property name="windowTitle"> | ||
| 14 | <string>Form</string> | ||
| 15 | </property> | ||
| 16 | <layout class="QVBoxLayout"> | ||
| 17 | <item> | ||
| 18 | <layout class="QVBoxLayout"> | ||
| 19 | <item> | ||
| 20 | <widget class="QGroupBox"> | ||
| 21 | <property name="title"> | ||
| 22 | <string>General</string> | ||
| 23 | </property> | ||
| 24 | <layout class="QVBoxLayout"> | ||
| 25 | <item> | ||
| 26 | <layout class="QHBoxLayout"> | ||
| 27 | <item> | ||
| 28 | <widget class="QLabel"> | ||
| 29 | <property name="text"> | ||
| 30 | <string>Accuracy:</string> | ||
| 31 | </property> | ||
| 32 | </widget> | ||
| 33 | </item> | ||
| 34 | <item> | ||
| 35 | <widget class="QComboBox" name="accuracy"> | ||
| 36 | <item> | ||
| 37 | <property name="text"> | ||
| 38 | <string>Accurate</string> | ||
| 39 | </property> | ||
| 40 | </item> | ||
| 41 | <item> | ||
| 42 | <property name="text"> | ||
| 43 | <string>Enable Debug Mode</string> | ||
| 44 | </property> | ||
| 45 | </item> | ||
| 46 | </widget> | ||
| 47 | </item> | ||
| 48 | </layout> | ||
| 49 | </item> | ||
| 50 | <item> | ||
| 51 | <widget class="QLabel"> | ||
| 52 | <property name="wordWrap"> | ||
| 53 | <bool>1</bool> | ||
| 54 | </property> | ||
| 55 | <property name="text"> | ||
| 56 | <string>We recommend setting accuracy to "Accurate".</string> | ||
| 57 | </property> | ||
| 58 | </widget> | ||
| 59 | </item> | ||
| 60 | </layout> | ||
| 61 | </widget> | ||
| 62 | </item> | ||
| 63 | </layout> | ||
| 64 | </item> | ||
| 65 | <item> | ||
| 66 | <spacer name="verticalSpacer"> | ||
| 67 | <property name="orientation"> | ||
| 68 | <enum>Qt::Vertical</enum> | ||
| 69 | </property> | ||
| 70 | <property name="sizeHint" stdset="0"> | ||
| 71 | <size> | ||
| 72 | <width>20</width> | ||
| 73 | <height>40</height> | ||
| 74 | </size> | ||
| 75 | </property> | ||
| 76 | </spacer> | ||
| 77 | </item> | ||
| 78 | <item> | ||
| 79 | <widget class="QLabel" name="label_disable_info"> | ||
| 80 | <property name="text"> | ||
| 81 | <string>CPU settings are available only when game is not running.</string> | ||
| 82 | </property> | ||
| 83 | <property name="wordWrap"> | ||
| 84 | <bool>true</bool> | ||
| 85 | </property> | ||
| 86 | </widget> | ||
| 87 | </item> | ||
| 88 | </layout> | ||
| 89 | </widget> | ||
| 90 | <resources/> | ||
| 91 | <connections/> | ||
| 92 | </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 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <QComboBox> | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "core/core.h" | ||
| 10 | #include "core/settings.h" | ||
| 11 | #include "ui_configure_cpu_debug.h" | ||
| 12 | #include "yuzu/configuration/configure_cpu_debug.h" | ||
| 13 | |||
| 14 | ConfigureCpuDebug::ConfigureCpuDebug(QWidget* parent) | ||
| 15 | : QWidget(parent), ui(new Ui::ConfigureCpuDebug) { | ||
| 16 | ui->setupUi(this); | ||
| 17 | |||
| 18 | SetConfiguration(); | ||
| 19 | } | ||
| 20 | |||
| 21 | ConfigureCpuDebug::~ConfigureCpuDebug() = default; | ||
| 22 | |||
| 23 | void ConfigureCpuDebug::SetConfiguration() { | ||
| 24 | const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); | ||
| 25 | |||
| 26 | ui->cpuopt_page_tables->setEnabled(runtime_lock); | ||
| 27 | ui->cpuopt_page_tables->setChecked(Settings::values.cpuopt_page_tables); | ||
| 28 | ui->cpuopt_block_linking->setEnabled(runtime_lock); | ||
| 29 | ui->cpuopt_block_linking->setChecked(Settings::values.cpuopt_block_linking); | ||
| 30 | ui->cpuopt_return_stack_buffer->setEnabled(runtime_lock); | ||
| 31 | ui->cpuopt_return_stack_buffer->setChecked(Settings::values.cpuopt_return_stack_buffer); | ||
| 32 | ui->cpuopt_fast_dispatcher->setEnabled(runtime_lock); | ||
| 33 | ui->cpuopt_fast_dispatcher->setChecked(Settings::values.cpuopt_fast_dispatcher); | ||
| 34 | ui->cpuopt_context_elimination->setEnabled(runtime_lock); | ||
| 35 | ui->cpuopt_context_elimination->setChecked(Settings::values.cpuopt_context_elimination); | ||
| 36 | ui->cpuopt_const_prop->setEnabled(runtime_lock); | ||
| 37 | ui->cpuopt_const_prop->setChecked(Settings::values.cpuopt_const_prop); | ||
| 38 | ui->cpuopt_misc_ir->setEnabled(runtime_lock); | ||
| 39 | ui->cpuopt_misc_ir->setChecked(Settings::values.cpuopt_misc_ir); | ||
| 40 | ui->cpuopt_reduce_misalign_checks->setEnabled(runtime_lock); | ||
| 41 | ui->cpuopt_reduce_misalign_checks->setChecked(Settings::values.cpuopt_reduce_misalign_checks); | ||
| 42 | } | ||
| 43 | |||
| 44 | void ConfigureCpuDebug::ApplyConfiguration() { | ||
| 45 | Settings::values.cpuopt_page_tables = ui->cpuopt_page_tables->isChecked(); | ||
| 46 | Settings::values.cpuopt_block_linking = ui->cpuopt_block_linking->isChecked(); | ||
| 47 | Settings::values.cpuopt_return_stack_buffer = ui->cpuopt_return_stack_buffer->isChecked(); | ||
| 48 | Settings::values.cpuopt_fast_dispatcher = ui->cpuopt_fast_dispatcher->isChecked(); | ||
| 49 | Settings::values.cpuopt_context_elimination = ui->cpuopt_context_elimination->isChecked(); | ||
| 50 | Settings::values.cpuopt_const_prop = ui->cpuopt_const_prop->isChecked(); | ||
| 51 | Settings::values.cpuopt_misc_ir = ui->cpuopt_misc_ir->isChecked(); | ||
| 52 | Settings::values.cpuopt_reduce_misalign_checks = ui->cpuopt_reduce_misalign_checks->isChecked(); | ||
| 53 | } | ||
| 54 | |||
| 55 | void ConfigureCpuDebug::changeEvent(QEvent* event) { | ||
| 56 | if (event->type() == QEvent::LanguageChange) { | ||
| 57 | RetranslateUI(); | ||
| 58 | } | ||
| 59 | |||
| 60 | QWidget::changeEvent(event); | ||
| 61 | } | ||
| 62 | |||
| 63 | void ConfigureCpuDebug::RetranslateUI() { | ||
| 64 | ui->retranslateUi(this); | ||
| 65 | } | ||
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 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <QWidget> | ||
| 9 | #include "core/settings.h" | ||
| 10 | |||
| 11 | namespace Ui { | ||
| 12 | class ConfigureCpuDebug; | ||
| 13 | } | ||
| 14 | |||
| 15 | class ConfigureCpuDebug : public QWidget { | ||
| 16 | Q_OBJECT | ||
| 17 | |||
| 18 | public: | ||
| 19 | explicit ConfigureCpuDebug(QWidget* parent = nullptr); | ||
| 20 | ~ConfigureCpuDebug() override; | ||
| 21 | |||
| 22 | void ApplyConfiguration(); | ||
| 23 | |||
| 24 | private: | ||
| 25 | void changeEvent(QEvent* event) override; | ||
| 26 | void RetranslateUI(); | ||
| 27 | |||
| 28 | void SetConfiguration(); | ||
| 29 | |||
| 30 | std::unique_ptr<Ui::ConfigureCpuDebug> ui; | ||
| 31 | }; | ||
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 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <ui version="4.0"> | ||
| 3 | <class>ConfigureCpuDebug</class> | ||
| 4 | <widget class="QWidget" name="ConfigureCpuDebug"> | ||
| 5 | <property name="geometry"> | ||
| 6 | <rect> | ||
| 7 | <x>0</x> | ||
| 8 | <y>0</y> | ||
| 9 | <width>400</width> | ||
| 10 | <height>321</height> | ||
| 11 | </rect> | ||
| 12 | </property> | ||
| 13 | <property name="windowTitle"> | ||
| 14 | <string>Form</string> | ||
| 15 | </property> | ||
| 16 | <layout class="QVBoxLayout"> | ||
| 17 | <item> | ||
| 18 | <layout class="QVBoxLayout"> | ||
| 19 | <item> | ||
| 20 | <widget class="QGroupBox"> | ||
| 21 | <property name="title"> | ||
| 22 | <string>Toggle CPU Optimizations</string> | ||
| 23 | </property> | ||
| 24 | <layout class="QVBoxLayout"> | ||
| 25 | <item> | ||
| 26 | <widget class="QLabel"> | ||
| 27 | <property name="wordWrap"> | ||
| 28 | <bool>1</bool> | ||
| 29 | </property> | ||
| 30 | <property name="text"> | ||
| 31 | <string> | ||
| 32 | <div> | ||
| 33 | <b>For debugging only.</b> | ||
| 34 | <br> | ||
| 35 | If you're not sure what these do, keep all of these enabled. | ||
| 36 | <br> | ||
| 37 | These settings only take effect when CPU Accuracy is "Debug Mode". | ||
| 38 | </div> | ||
| 39 | </string> | ||
| 40 | </property> | ||
| 41 | </widget> | ||
| 42 | </item> | ||
| 43 | <item> | ||
| 44 | <widget class="QCheckBox" name="cpuopt_page_tables"> | ||
| 45 | <property name="text"> | ||
| 46 | <string>Enable inline page tables</string> | ||
| 47 | </property> | ||
| 48 | <property name="toolTip"> | ||
| 49 | <string> | ||
| 50 | <div style="white-space: nowrap">This optimization speeds up memory accesses by the guest program.</div> | ||
| 51 | <div style="white-space: nowrap">Enabling it inlines accesses to PageTable::pointers into emitted code.</div> | ||
| 52 | <div style="white-space: nowrap">Disabling this forces all memory accesses to go through the Memory::Read/Memory::Write functions.</div> | ||
| 53 | </string> | ||
| 54 | </property> | ||
| 55 | </widget> | ||
| 56 | </item> | ||
| 57 | <item> | ||
| 58 | <widget class="QCheckBox" name="cpuopt_block_linking"> | ||
| 59 | <property name="text"> | ||
| 60 | <string>Enable block linking</string> | ||
| 61 | </property> | ||
| 62 | <property name="toolTip"> | ||
| 63 | <string> | ||
| 64 | <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> | ||
| 65 | </string> | ||
| 66 | </property> | ||
| 67 | </widget> | ||
| 68 | </item> | ||
| 69 | <item> | ||
| 70 | <widget class="QCheckBox" name="cpuopt_return_stack_buffer"> | ||
| 71 | <property name="text"> | ||
| 72 | <string>Enable return stack buffer</string> | ||
| 73 | </property> | ||
| 74 | <property name="toolTip"> | ||
| 75 | <string> | ||
| 76 | <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> | ||
| 77 | </string> | ||
| 78 | </property> | ||
| 79 | </widget> | ||
| 80 | </item> | ||
| 81 | <item> | ||
| 82 | <widget class="QCheckBox" name="cpuopt_fast_dispatcher"> | ||
| 83 | <property name="text"> | ||
| 84 | <string>Enable fast dispatcher</string> | ||
| 85 | </property> | ||
| 86 | <property name="toolTip"> | ||
| 87 | <string> | ||
| 88 | <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> | ||
| 89 | </string> | ||
| 90 | </property> | ||
| 91 | </widget> | ||
| 92 | </item> | ||
| 93 | <item> | ||
| 94 | <widget class="QCheckBox" name="cpuopt_context_elimination"> | ||
| 95 | <property name="text"> | ||
| 96 | <string>Enable context elimination</string> | ||
| 97 | </property> | ||
| 98 | <property name="toolTip"> | ||
| 99 | <string> | ||
| 100 | <div>Enables an IR optimization that reduces unnecessary accesses to the CPU context structure.</div> | ||
| 101 | </string> | ||
| 102 | </property> | ||
| 103 | </widget> | ||
| 104 | </item> | ||
| 105 | <item> | ||
| 106 | <widget class="QCheckBox" name="cpuopt_const_prop"> | ||
| 107 | <property name="text"> | ||
| 108 | <string>Enable constant propagation</string> | ||
| 109 | </property> | ||
| 110 | <property name="toolTip"> | ||
| 111 | <string> | ||
| 112 | <div>Enables IR optimizations that involve constant propagation.</div> | ||
| 113 | </string> | ||
| 114 | </property> | ||
| 115 | </widget> | ||
| 116 | </item> | ||
| 117 | <item> | ||
| 118 | <widget class="QCheckBox" name="cpuopt_misc_ir"> | ||
| 119 | <property name="text"> | ||
| 120 | <string>Enable miscellaneous optimizations</string> | ||
| 121 | </property> | ||
| 122 | <property name="toolTip"> | ||
| 123 | <string> | ||
| 124 | <div>Enables miscellaneous IR optimizations.</div> | ||
| 125 | </string> | ||
| 126 | </property> | ||
| 127 | </widget> | ||
| 128 | </item> | ||
| 129 | <item> | ||
| 130 | <widget class="QCheckBox" name="cpuopt_reduce_misalign_checks"> | ||
| 131 | <property name="text"> | ||
| 132 | <string>Enable misalignment check reduction</string> | ||
| 133 | </property> | ||
| 134 | <property name="toolTip"> | ||
| 135 | <string> | ||
| 136 | <div style="white-space: nowrap">When enabled, a misalignment is only triggered when an access crosses a page boundary.</div> | ||
| 137 | <div style="white-space: nowrap">When disabled, a misalignment is triggered on all misaligned accesses.</div> | ||
| 138 | </string> | ||
| 139 | </property> | ||
| 140 | </widget> | ||
| 141 | </item> | ||
| 142 | </layout> | ||
| 143 | </widget> | ||
| 144 | </item> | ||
| 145 | </layout> | ||
| 146 | </item> | ||
| 147 | <item> | ||
| 148 | <spacer name="verticalSpacer"> | ||
| 149 | <property name="orientation"> | ||
| 150 | <enum>Qt::Vertical</enum> | ||
| 151 | </property> | ||
| 152 | <property name="sizeHint" stdset="0"> | ||
| 153 | <size> | ||
| 154 | <width>20</width> | ||
| 155 | <height>40</height> | ||
| 156 | </size> | ||
| 157 | </property> | ||
| 158 | </spacer> | ||
| 159 | </item> | ||
| 160 | <item> | ||
| 161 | <widget class="QLabel" name="label_disable_info"> | ||
| 162 | <property name="text"> | ||
| 163 | <string>CPU settings are available only when game is not running.</string> | ||
| 164 | </property> | ||
| 165 | <property name="wordWrap"> | ||
| 166 | <bool>true</bool> | ||
| 167 | </property> | ||
| 168 | </widget> | ||
| 169 | </item> | ||
| 170 | </layout> | ||
| 171 | </widget> | ||
| 172 | <resources/> | ||
| 173 | <connections/> | ||
| 174 | </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() { | |||
| 36 | ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args)); | 36 | ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args)); |
| 37 | ui->reporting_services->setChecked(Settings::values.reporting_services); | 37 | ui->reporting_services->setChecked(Settings::values.reporting_services); |
| 38 | ui->quest_flag->setChecked(Settings::values.quest_flag); | 38 | ui->quest_flag->setChecked(Settings::values.quest_flag); |
| 39 | ui->disable_cpu_opt->setChecked(Settings::values.disable_cpu_opt); | ||
| 40 | ui->enable_graphics_debugging->setEnabled(!Core::System::GetInstance().IsPoweredOn()); | 39 | ui->enable_graphics_debugging->setEnabled(!Core::System::GetInstance().IsPoweredOn()); |
| 41 | ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug); | 40 | ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug); |
| 42 | ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); | 41 | ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); |
| @@ -51,7 +50,6 @@ void ConfigureDebug::ApplyConfiguration() { | |||
| 51 | Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); | 50 | Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); |
| 52 | Settings::values.reporting_services = ui->reporting_services->isChecked(); | 51 | Settings::values.reporting_services = ui->reporting_services->isChecked(); |
| 53 | Settings::values.quest_flag = ui->quest_flag->isChecked(); | 52 | Settings::values.quest_flag = ui->quest_flag->isChecked(); |
| 54 | Settings::values.disable_cpu_opt = ui->disable_cpu_opt->isChecked(); | ||
| 55 | Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); | 53 | Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); |
| 56 | Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); | 54 | Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); |
| 57 | Debugger::ToggleConsole(); | 55 | 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 @@ | |||
| 228 | </property> | 228 | </property> |
| 229 | </widget> | 229 | </widget> |
| 230 | </item> | 230 | </item> |
| 231 | <item> | ||
| 232 | <widget class="QCheckBox" name="disable_cpu_opt"> | ||
| 233 | <property name="text"> | ||
| 234 | <string>Disable CPU JIT optimizations</string> | ||
| 235 | </property> | ||
| 236 | </widget> | ||
| 237 | </item> | ||
| 238 | </layout> | 231 | </layout> |
| 239 | </widget> | 232 | </widget> |
| 240 | </item> | 233 | </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() { | |||
| 42 | ui->filesystemTab->applyConfiguration(); | 42 | ui->filesystemTab->applyConfiguration(); |
| 43 | ui->inputTab->ApplyConfiguration(); | 43 | ui->inputTab->ApplyConfiguration(); |
| 44 | ui->hotkeysTab->ApplyConfiguration(registry); | 44 | ui->hotkeysTab->ApplyConfiguration(registry); |
| 45 | ui->cpuTab->ApplyConfiguration(); | ||
| 46 | ui->cpuDebugTab->ApplyConfiguration(); | ||
| 45 | ui->graphicsTab->ApplyConfiguration(); | 47 | ui->graphicsTab->ApplyConfiguration(); |
| 46 | ui->graphicsAdvancedTab->ApplyConfiguration(); | 48 | ui->graphicsAdvancedTab->ApplyConfiguration(); |
| 47 | ui->audioTab->ApplyConfiguration(); | 49 | ui->audioTab->ApplyConfiguration(); |
| @@ -76,9 +78,10 @@ void ConfigureDialog::RetranslateUI() { | |||
| 76 | Q_DECLARE_METATYPE(QList<QWidget*>); | 78 | Q_DECLARE_METATYPE(QList<QWidget*>); |
| 77 | 79 | ||
| 78 | void ConfigureDialog::PopulateSelectionList() { | 80 | void ConfigureDialog::PopulateSelectionList() { |
| 79 | const std::array<std::pair<QString, QList<QWidget*>>, 5> items{ | 81 | const std::array<std::pair<QString, QList<QWidget*>>, 6> items{ |
| 80 | {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->uiTab}}, | 82 | {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->uiTab}}, |
| 81 | {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}}, | 83 | {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}}, |
| 84 | {tr("CPU"), {ui->cpuTab, ui->cpuDebugTab}}, | ||
| 82 | {tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}}, | 85 | {tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}}, |
| 83 | {tr("Audio"), {ui->audioTab}}, | 86 | {tr("Audio"), {ui->audioTab}}, |
| 84 | {tr("Controls"), {ui->inputTab, ui->hotkeysTab}}}, | 87 | {tr("Controls"), {ui->inputTab, ui->hotkeysTab}}}, |
| @@ -107,6 +110,8 @@ void ConfigureDialog::UpdateVisibleTabs() { | |||
| 107 | {ui->profileManagerTab, tr("Profiles")}, | 110 | {ui->profileManagerTab, tr("Profiles")}, |
| 108 | {ui->inputTab, tr("Input")}, | 111 | {ui->inputTab, tr("Input")}, |
| 109 | {ui->hotkeysTab, tr("Hotkeys")}, | 112 | {ui->hotkeysTab, tr("Hotkeys")}, |
| 113 | {ui->cpuTab, tr("CPU")}, | ||
| 114 | {ui->cpuDebugTab, tr("Debug")}, | ||
| 110 | {ui->graphicsTab, tr("Graphics")}, | 115 | {ui->graphicsTab, tr("Graphics")}, |
| 111 | {ui->graphicsAdvancedTab, tr("Advanced")}, | 116 | {ui->graphicsAdvancedTab, tr("Advanced")}, |
| 112 | {ui->audioTab, tr("Audio")}, | 117 | {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 @@ | |||
| 11 | #include "yuzu/configuration/configure_filesystem.h" | 11 | #include "yuzu/configuration/configure_filesystem.h" |
| 12 | #include "yuzu/uisettings.h" | 12 | #include "yuzu/uisettings.h" |
| 13 | 13 | ||
| 14 | namespace { | ||
| 15 | |||
| 16 | template <typename T> | ||
| 17 | void SetComboBoxFromData(QComboBox* combo_box, T data) { | ||
| 18 | const auto index = combo_box->findData(QVariant::fromValue(static_cast<u64>(data))); | ||
| 19 | if (index >= combo_box->count() || index < 0) | ||
| 20 | return; | ||
| 21 | |||
| 22 | combo_box->setCurrentIndex(index); | ||
| 23 | } | ||
| 24 | |||
| 25 | } // Anonymous namespace | ||
| 26 | |||
| 27 | ConfigureFilesystem::ConfigureFilesystem(QWidget* parent) | 14 | ConfigureFilesystem::ConfigureFilesystem(QWidget* parent) |
| 28 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureFilesystem>()) { | 15 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureFilesystem>()) { |
| 29 | ui->setupUi(this); | 16 | ui->setupUi(this); |
| @@ -73,11 +60,6 @@ void ConfigureFilesystem::setConfiguration() { | |||
| 73 | 60 | ||
| 74 | ui->cache_game_list->setChecked(UISettings::values.cache_game_list); | 61 | ui->cache_game_list->setChecked(UISettings::values.cache_game_list); |
| 75 | 62 | ||
| 76 | SetComboBoxFromData(ui->nand_size, Settings::values.nand_total_size); | ||
| 77 | SetComboBoxFromData(ui->usrnand_size, Settings::values.nand_user_size); | ||
| 78 | SetComboBoxFromData(ui->sysnand_size, Settings::values.nand_system_size); | ||
| 79 | SetComboBoxFromData(ui->sdmc_size, Settings::values.sdmc_size); | ||
| 80 | |||
| 81 | UpdateEnabledControls(); | 63 | UpdateEnabledControls(); |
| 82 | } | 64 | } |
| 83 | 65 | ||
| @@ -98,15 +80,6 @@ void ConfigureFilesystem::applyConfiguration() { | |||
| 98 | Settings::values.dump_nso = ui->dump_nso->isChecked(); | 80 | Settings::values.dump_nso = ui->dump_nso->isChecked(); |
| 99 | 81 | ||
| 100 | UISettings::values.cache_game_list = ui->cache_game_list->isChecked(); | 82 | UISettings::values.cache_game_list = ui->cache_game_list->isChecked(); |
| 101 | |||
| 102 | Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>( | ||
| 103 | ui->nand_size->itemData(ui->nand_size->currentIndex()).toULongLong()); | ||
| 104 | Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>( | ||
| 105 | ui->nand_size->itemData(ui->sysnand_size->currentIndex()).toULongLong()); | ||
| 106 | Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>( | ||
| 107 | ui->nand_size->itemData(ui->usrnand_size->currentIndex()).toULongLong()); | ||
| 108 | Settings::values.sdmc_size = static_cast<Settings::SDMCSize>( | ||
| 109 | ui->nand_size->itemData(ui->sdmc_size->currentIndex()).toULongLong()); | ||
| 110 | } | 83 | } |
| 111 | 84 | ||
| 112 | void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit) { | 85 | 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 @@ | |||
| 116 | </widget> | 116 | </widget> |
| 117 | </item> | 117 | </item> |
| 118 | <item> | 118 | <item> |
| 119 | <widget class="QGroupBox" name="groupBox_3"> | ||
| 120 | <property name="title"> | ||
| 121 | <string>Storage Sizes</string> | ||
| 122 | </property> | ||
| 123 | <layout class="QGridLayout" name="gridLayout_3"> | ||
| 124 | <item row="3" column="0"> | ||
| 125 | <widget class="QLabel" name="label_5"> | ||
| 126 | <property name="text"> | ||
| 127 | <string>SD Card</string> | ||
| 128 | </property> | ||
| 129 | </widget> | ||
| 130 | </item> | ||
| 131 | <item row="1" column="0"> | ||
| 132 | <widget class="QLabel" name="label_4"> | ||
| 133 | <property name="text"> | ||
| 134 | <string>System NAND</string> | ||
| 135 | </property> | ||
| 136 | </widget> | ||
| 137 | </item> | ||
| 138 | <item row="1" column="1"> | ||
| 139 | <widget class="QComboBox" name="sysnand_size"> | ||
| 140 | <item> | ||
| 141 | <property name="text"> | ||
| 142 | <string>2.5 GB</string> | ||
| 143 | </property> | ||
| 144 | </item> | ||
| 145 | </widget> | ||
| 146 | </item> | ||
| 147 | <item row="3" column="1"> | ||
| 148 | <widget class="QComboBox" name="sdmc_size"> | ||
| 149 | <property name="currentText"> | ||
| 150 | <string>32 GB</string> | ||
| 151 | </property> | ||
| 152 | <item> | ||
| 153 | <property name="text"> | ||
| 154 | <string>1 GB</string> | ||
| 155 | </property> | ||
| 156 | </item> | ||
| 157 | <item> | ||
| 158 | <property name="text"> | ||
| 159 | <string>2 GB</string> | ||
| 160 | </property> | ||
| 161 | </item> | ||
| 162 | <item> | ||
| 163 | <property name="text"> | ||
| 164 | <string>4 GB</string> | ||
| 165 | </property> | ||
| 166 | </item> | ||
| 167 | <item> | ||
| 168 | <property name="text"> | ||
| 169 | <string>8 GB</string> | ||
| 170 | </property> | ||
| 171 | </item> | ||
| 172 | <item> | ||
| 173 | <property name="text"> | ||
| 174 | <string>16 GB</string> | ||
| 175 | </property> | ||
| 176 | </item> | ||
| 177 | <item> | ||
| 178 | <property name="text"> | ||
| 179 | <string>32 GB</string> | ||
| 180 | </property> | ||
| 181 | </item> | ||
| 182 | <item> | ||
| 183 | <property name="text"> | ||
| 184 | <string>64 GB</string> | ||
| 185 | </property> | ||
| 186 | </item> | ||
| 187 | <item> | ||
| 188 | <property name="text"> | ||
| 189 | <string>128 GB</string> | ||
| 190 | </property> | ||
| 191 | </item> | ||
| 192 | <item> | ||
| 193 | <property name="text"> | ||
| 194 | <string>256 GB</string> | ||
| 195 | </property> | ||
| 196 | </item> | ||
| 197 | <item> | ||
| 198 | <property name="text"> | ||
| 199 | <string>1 TB</string> | ||
| 200 | </property> | ||
| 201 | </item> | ||
| 202 | </widget> | ||
| 203 | </item> | ||
| 204 | <item row="2" column="1"> | ||
| 205 | <widget class="QComboBox" name="usrnand_size"> | ||
| 206 | <item> | ||
| 207 | <property name="text"> | ||
| 208 | <string>26 GB</string> | ||
| 209 | </property> | ||
| 210 | </item> | ||
| 211 | </widget> | ||
| 212 | </item> | ||
| 213 | <item row="2" column="0"> | ||
| 214 | <widget class="QLabel" name="label_6"> | ||
| 215 | <property name="text"> | ||
| 216 | <string>User NAND</string> | ||
| 217 | </property> | ||
| 218 | </widget> | ||
| 219 | </item> | ||
| 220 | <item row="0" column="0"> | ||
| 221 | <widget class="QLabel" name="label_7"> | ||
| 222 | <property name="text"> | ||
| 223 | <string>NAND</string> | ||
| 224 | </property> | ||
| 225 | </widget> | ||
| 226 | </item> | ||
| 227 | <item row="0" column="1"> | ||
| 228 | <widget class="QComboBox" name="nand_size"> | ||
| 229 | <item> | ||
| 230 | <property name="text"> | ||
| 231 | <string>29.1 GB</string> | ||
| 232 | </property> | ||
| 233 | </item> | ||
| 234 | </widget> | ||
| 235 | </item> | ||
| 236 | </layout> | ||
| 237 | </widget> | ||
| 238 | </item> | ||
| 239 | <item> | ||
| 240 | <widget class="QGroupBox" name="groupBox_4"> | 119 | <widget class="QGroupBox" name="groupBox_4"> |
| 241 | <property name="title"> | 120 | <property name="title"> |
| 242 | <string>Patch Manager</string> | 121 | <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() { | |||
| 65 | Settings::values.use_frame_limit.SetValue(ui->toggle_frame_limit->checkState() == | 65 | Settings::values.use_frame_limit.SetValue(ui->toggle_frame_limit->checkState() == |
| 66 | Qt::Checked); | 66 | Qt::Checked); |
| 67 | Settings::values.frame_limit.SetValue(ui->frame_limit->value()); | 67 | Settings::values.frame_limit.SetValue(ui->frame_limit->value()); |
| 68 | } | ||
| 69 | if (Settings::values.use_multi_core.UsingGlobal()) { | ||
| 68 | Settings::values.use_multi_core.SetValue(ui->use_multi_core->isChecked()); | 70 | Settings::values.use_multi_core.SetValue(ui->use_multi_core->isChecked()); |
| 69 | } | 71 | } |
| 70 | } else { | 72 | } else { |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 432379705..9f758605a 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -279,17 +279,21 @@ GMainWindow::~GMainWindow() { | |||
| 279 | } | 279 | } |
| 280 | 280 | ||
| 281 | void GMainWindow::ProfileSelectorSelectProfile() { | 281 | void GMainWindow::ProfileSelectorSelectProfile() { |
| 282 | QtProfileSelectionDialog dialog(this); | 282 | const Service::Account::ProfileManager manager; |
| 283 | dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | | 283 | int index = 0; |
| 284 | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); | 284 | if (manager.GetUserCount() != 1) { |
| 285 | dialog.setWindowModality(Qt::WindowModal); | 285 | QtProfileSelectionDialog dialog(this); |
| 286 | if (dialog.exec() == QDialog::Rejected) { | 286 | dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | |
| 287 | emit ProfileSelectorFinishedSelection(std::nullopt); | 287 | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); |
| 288 | return; | 288 | dialog.setWindowModality(Qt::WindowModal); |
| 289 | if (dialog.exec() == QDialog::Rejected) { | ||
| 290 | emit ProfileSelectorFinishedSelection(std::nullopt); | ||
| 291 | return; | ||
| 292 | } | ||
| 293 | index = dialog.GetIndex(); | ||
| 289 | } | 294 | } |
| 290 | 295 | ||
| 291 | Service::Account::ProfileManager manager; | 296 | const auto uuid = manager.GetUser(static_cast<std::size_t>(index)); |
| 292 | const auto uuid = manager.GetUser(static_cast<std::size_t>(dialog.GetIndex())); | ||
| 293 | if (!uuid.has_value()) { | 297 | if (!uuid.has_value()) { |
| 294 | emit ProfileSelectorFinishedSelection(std::nullopt); | 298 | emit ProfileSelectorFinishedSelection(std::nullopt); |
| 295 | return; | 299 | return; |
| @@ -1755,7 +1759,7 @@ InstallResult GMainWindow::InstallNSPXCI(const QString& filename) { | |||
| 1755 | *nsp, true, qt_raw_copy); | 1759 | *nsp, true, qt_raw_copy); |
| 1756 | if (res == FileSys::InstallResult::Success) { | 1760 | if (res == FileSys::InstallResult::Success) { |
| 1757 | return InstallResult::Success; | 1761 | return InstallResult::Success; |
| 1758 | } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { | 1762 | } else if (res == FileSys::InstallResult::OverwriteExisting) { |
| 1759 | return InstallResult::Overwrite; | 1763 | return InstallResult::Overwrite; |
| 1760 | } else { | 1764 | } else { |
| 1761 | return InstallResult::Failure; | 1765 | return InstallResult::Failure; |
| @@ -1842,7 +1846,7 @@ InstallResult GMainWindow::InstallNCA(const QString& filename) { | |||
| 1842 | 1846 | ||
| 1843 | if (res == FileSys::InstallResult::Success) { | 1847 | if (res == FileSys::InstallResult::Success) { |
| 1844 | return InstallResult::Success; | 1848 | return InstallResult::Success; |
| 1845 | } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { | 1849 | } else if (res == FileSys::InstallResult::OverwriteExisting) { |
| 1846 | return InstallResult::Overwrite; | 1850 | return InstallResult::Overwrite; |
| 1847 | } else { | 1851 | } else { |
| 1848 | return InstallResult::Failure; | 1852 | return InstallResult::Failure; |
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() { | |||
| 335 | Settings::values.gamecard_current_game = | 335 | Settings::values.gamecard_current_game = |
| 336 | sdl2_config->GetBoolean("Data Storage", "gamecard_current_game", false); | 336 | sdl2_config->GetBoolean("Data Storage", "gamecard_current_game", false); |
| 337 | Settings::values.gamecard_path = sdl2_config->Get("Data Storage", "gamecard_path", ""); | 337 | Settings::values.gamecard_path = sdl2_config->Get("Data Storage", "gamecard_path", ""); |
| 338 | Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(sdl2_config->GetInteger( | ||
| 339 | "Data Storage", "nand_total_size", static_cast<long>(Settings::NANDTotalSize::S29_1GB))); | ||
| 340 | Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(sdl2_config->GetInteger( | ||
| 341 | "Data Storage", "nand_user_size", static_cast<long>(Settings::NANDUserSize::S26GB))); | ||
| 342 | Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>( | ||
| 343 | sdl2_config->GetInteger("Data Storage", "nand_system_size", | ||
| 344 | static_cast<long>(Settings::NANDSystemSize::S2_5GB))); | ||
| 345 | Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(sdl2_config->GetInteger( | ||
| 346 | "Data Storage", "sdmc_size", static_cast<long>(Settings::SDMCSize::S16GB))); | ||
| 347 | 338 | ||
| 348 | // System | 339 | // System |
| 349 | Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false); | 340 | Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false); |
| @@ -437,8 +428,6 @@ void Config::ReadValues() { | |||
| 437 | Settings::values.reporting_services = | 428 | Settings::values.reporting_services = |
| 438 | sdl2_config->GetBoolean("Debugging", "reporting_services", false); | 429 | sdl2_config->GetBoolean("Debugging", "reporting_services", false); |
| 439 | Settings::values.quest_flag = sdl2_config->GetBoolean("Debugging", "quest_flag", false); | 430 | Settings::values.quest_flag = sdl2_config->GetBoolean("Debugging", "quest_flag", false); |
| 440 | Settings::values.disable_cpu_opt = | ||
| 441 | sdl2_config->GetBoolean("Debugging", "disable_cpu_opt", false); | ||
| 442 | Settings::values.disable_macro_jit = | 431 | Settings::values.disable_macro_jit = |
| 443 | sdl2_config->GetBoolean("Debugging", "disable_macro_jit", false); | 432 | sdl2_config->GetBoolean("Debugging", "disable_macro_jit", false); |
| 444 | 433 | ||
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= | |||
| 97 | # 0 (default): Disabled, 1: Enabled | 97 | # 0 (default): Disabled, 1: Enabled |
| 98 | use_multi_core= | 98 | use_multi_core= |
| 99 | 99 | ||
| 100 | [Cpu] | ||
| 101 | # Enable inline page tables optimization (faster guest memory access) | ||
| 102 | # 0: Disabled, 1 (default): Enabled | ||
| 103 | cpuopt_page_tables = | ||
| 104 | |||
| 105 | # Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps) | ||
| 106 | # 0: Disabled, 1 (default): Enabled | ||
| 107 | cpuopt_block_linking = | ||
| 108 | |||
| 109 | # Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns) | ||
| 110 | # 0: Disabled, 1 (default): Enabled | ||
| 111 | cpuopt_return_stack_buffer = | ||
| 112 | |||
| 113 | # Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture) | ||
| 114 | # 0: Disabled, 1 (default): Enabled | ||
| 115 | cpuopt_fast_dispatcher = | ||
| 116 | |||
| 117 | # Enable context elimination CPU Optimization (reduce host memory use for guest context) | ||
| 118 | # 0: Disabled, 1 (default): Enabled | ||
| 119 | cpuopt_context_elimination = | ||
| 120 | |||
| 121 | # Enable constant propagation CPU optimization (basic IR optimization) | ||
| 122 | # 0: Disabled, 1 (default): Enabled | ||
| 123 | cpuopt_const_prop = | ||
| 124 | |||
| 125 | # Enable miscellaneous CPU optimizations (basic IR optimization) | ||
| 126 | # 0: Disabled, 1 (default): Enabled | ||
| 127 | cpuopt_misc_ir = | ||
| 128 | |||
| 129 | # Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access) | ||
| 130 | # 0: Disabled, 1 (default): Enabled | ||
| 131 | cpuopt_reduce_misalign_checks = | ||
| 132 | |||
| 100 | [Renderer] | 133 | [Renderer] |
| 101 | # Which backend API to use. | 134 | # Which backend API to use. |
| 102 | # 0 (default): OpenGL, 1: Vulkan | 135 | # 0 (default): OpenGL, 1: Vulkan |
| @@ -283,9 +316,6 @@ dump_nso=false | |||
| 283 | # Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode | 316 | # Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode |
| 284 | # false: Retail/Normal Mode (default), true: Kiosk Mode | 317 | # false: Retail/Normal Mode (default), true: Kiosk Mode |
| 285 | quest_flag = | 318 | quest_flag = |
| 286 | # Determines whether or not JIT CPU optimizations are enabled | ||
| 287 | # false: Optimizations Enabled, true: Optimizations Disabled | ||
| 288 | disable_cpu_opt = | ||
| 289 | # Enables/Disables the macro JIT compiler | 319 | # Enables/Disables the macro JIT compiler |
| 290 | disable_macro_jit=false | 320 | disable_macro_jit=false |
| 291 | 321 | ||
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"( | |||
| 12 | # 0 (default): Disabled, 1: Enabled | 12 | # 0 (default): Disabled, 1: Enabled |
| 13 | use_multi_core= | 13 | use_multi_core= |
| 14 | 14 | ||
| 15 | [Cpu] | ||
| 16 | # Enable inline page tables optimization (faster guest memory access) | ||
| 17 | # 0: Disabled, 1 (default): Enabled | ||
| 18 | cpuopt_page_tables = | ||
| 19 | |||
| 20 | # Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps) | ||
| 21 | # 0: Disabled, 1 (default): Enabled | ||
| 22 | cpuopt_block_linking = | ||
| 23 | |||
| 24 | # Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns) | ||
| 25 | # 0: Disabled, 1 (default): Enabled | ||
| 26 | cpuopt_return_stack_buffer = | ||
| 27 | |||
| 28 | # Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture) | ||
| 29 | # 0: Disabled, 1 (default): Enabled | ||
| 30 | cpuopt_fast_dispatcher = | ||
| 31 | |||
| 32 | # Enable context elimination CPU Optimization (reduce host memory use for guest context) | ||
| 33 | # 0: Disabled, 1 (default): Enabled | ||
| 34 | cpuopt_context_elimination = | ||
| 35 | |||
| 36 | # Enable constant propagation CPU optimization (basic IR optimization) | ||
| 37 | # 0: Disabled, 1 (default): Enabled | ||
| 38 | cpuopt_const_prop = | ||
| 39 | |||
| 40 | # Enable miscellaneous CPU optimizations (basic IR optimization) | ||
| 41 | # 0: Disabled, 1 (default): Enabled | ||
| 42 | cpuopt_misc_ir = | ||
| 43 | |||
| 44 | # Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access) | ||
| 45 | # 0: Disabled, 1 (default): Enabled | ||
| 46 | cpuopt_reduce_misalign_checks = | ||
| 47 | |||
| 15 | [Renderer] | 48 | [Renderer] |
| 16 | # Whether to use software or hardware rendering. | 49 | # Whether to use software or hardware rendering. |
| 17 | # 0: Software, 1 (default): Hardware | 50 | # 0: Software, 1 (default): Hardware |