diff options
40 files changed, 1227 insertions, 687 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 99476c55f..ce46a2c2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -118,15 +118,15 @@ message(STATUS "Target architecture: ${ARCHITECTURE}") | |||
| 118 | # Configure C++ standard | 118 | # Configure C++ standard |
| 119 | # =========================== | 119 | # =========================== |
| 120 | 120 | ||
| 121 | # boost asio's concept usage doesn't play nicely with some compilers yet. | ||
| 122 | add_definitions(-DBOOST_ASIO_DISABLE_CONCEPTS) | ||
| 121 | if (MSVC) | 123 | if (MSVC) |
| 122 | add_compile_options(/std:c++latest) | 124 | add_compile_options(/std:c++latest) |
| 123 | 125 | ||
| 124 | # cubeb and boost still make use of deprecated result_of. | 126 | # cubeb and boost still make use of deprecated result_of. |
| 125 | add_definitions(-D_HAS_DEPRECATED_RESULT_OF) | 127 | add_definitions(-D_HAS_DEPRECATED_RESULT_OF) |
| 126 | # boost asio's concept usage doesn't play nicely with MSVC yet. | ||
| 127 | add_definitions(-DBOOST_ASIO_DISABLE_CONCEPTS) | ||
| 128 | else() | 128 | else() |
| 129 | set(CMAKE_CXX_STANDARD 17) | 129 | set(CMAKE_CXX_STANDARD 20) |
| 130 | set(CMAKE_CXX_STANDARD_REQUIRED ON) | 130 | set(CMAKE_CXX_STANDARD_REQUIRED ON) |
| 131 | endif() | 131 | endif() |
| 132 | 132 | ||
| @@ -345,6 +345,7 @@ if(NOT APPLE) | |||
| 345 | endif() | 345 | endif() |
| 346 | if (NOT LIBUSB_FOUND) | 346 | if (NOT LIBUSB_FOUND) |
| 347 | add_subdirectory(externals/libusb) | 347 | add_subdirectory(externals/libusb) |
| 348 | set(LIBUSB_INCLUDE_DIR "") | ||
| 348 | set(LIBUSB_LIBRARIES usb) | 349 | set(LIBUSB_LIBRARIES usb) |
| 349 | endif() | 350 | endif() |
| 350 | 351 | ||
diff --git a/externals/dynarmic b/externals/dynarmic | |||
| Subproject 4f967387c07365b7ea35d2fa3e19b7df8872a09 | Subproject 82417da7803e2cf18efc28a1cd3f3d0a4b6045a | ||
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/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/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/settings.h b/src/core/settings.h index 850ca4072..3eb336f75 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 |
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..38210ffcb 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 | ||
| @@ -33,7 +34,7 @@ Adapter::Adapter() { | |||
| 33 | } | 34 | } |
| 34 | } | 35 | } |
| 35 | 36 | ||
| 36 | GCPadStatus Adapter::GetPadStatus(int port, const std::array<u8, 37>& adapter_payload) { | 37 | GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload) { |
| 37 | GCPadStatus pad = {}; | 38 | GCPadStatus pad = {}; |
| 38 | bool get_origin = false; | 39 | bool get_origin = false; |
| 39 | 40 | ||
| @@ -198,7 +199,7 @@ void Adapter::StartScanThread() { | |||
| 198 | } | 199 | } |
| 199 | 200 | ||
| 200 | detect_thread_running = true; | 201 | detect_thread_running = true; |
| 201 | detect_thread = std::thread([=] { ScanThreadFunc(); }); | 202 | detect_thread = std::thread(&Adapter::ScanThreadFunc, this); |
| 202 | } | 203 | } |
| 203 | 204 | ||
| 204 | void Adapter::StopScanThread() { | 205 | void Adapter::StopScanThread() { |
| @@ -227,7 +228,7 @@ void Adapter::Setup() { | |||
| 227 | } | 228 | } |
| 228 | 229 | ||
| 229 | if (devices != nullptr) { | 230 | if (devices != nullptr) { |
| 230 | for (std::size_t index = 0; index < device_count; ++index) { | 231 | for (std::size_t index = 0; index < static_cast<std::size_t>(device_count); ++index) { |
| 231 | if (CheckDeviceAccess(devices[index])) { | 232 | if (CheckDeviceAccess(devices[index])) { |
| 232 | // GC Adapter found and accessible, registering it | 233 | // GC Adapter found and accessible, registering it |
| 233 | GetGCEndpoint(devices[index]); | 234 | GetGCEndpoint(devices[index]); |
| @@ -357,11 +358,11 @@ void Adapter::Reset() { | |||
| 357 | } | 358 | } |
| 358 | } | 359 | } |
| 359 | 360 | ||
| 360 | bool Adapter::DeviceConnected(int port) { | 361 | bool Adapter::DeviceConnected(std::size_t port) { |
| 361 | return adapter_controllers_status[port] != ControllerTypes::None; | 362 | return adapter_controllers_status[port] != ControllerTypes::None; |
| 362 | } | 363 | } |
| 363 | 364 | ||
| 364 | void Adapter::ResetDeviceType(int port) { | 365 | void Adapter::ResetDeviceType(std::size_t port) { |
| 365 | adapter_controllers_status[port] = ControllerTypes::None; | 366 | adapter_controllers_status[port] = ControllerTypes::None; |
| 366 | } | 367 | } |
| 367 | 368 | ||
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h index b1c2a1958..e2cdd6255 100644 --- a/src/input_common/gcadapter/gc_adapter.h +++ b/src/input_common/gcadapter/gc_adapter.h | |||
| @@ -8,10 +8,13 @@ | |||
| 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 | ||
| 14 | struct libusb_context; | ||
| 15 | struct libusb_device; | ||
| 16 | struct libusb_device_handle; | ||
| 17 | |||
| 15 | namespace GCAdapter { | 18 | namespace GCAdapter { |
| 16 | 19 | ||
| 17 | enum { | 20 | enum { |
| @@ -97,6 +100,9 @@ public: | |||
| 97 | void BeginConfiguration(); | 100 | void BeginConfiguration(); |
| 98 | void EndConfiguration(); | 101 | void EndConfiguration(); |
| 99 | 102 | ||
| 103 | /// Returns true if there is a device connected to port | ||
| 104 | bool DeviceConnected(std::size_t port); | ||
| 105 | |||
| 100 | std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue(); | 106 | std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue(); |
| 101 | const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const; | 107 | const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const; |
| 102 | 108 | ||
| @@ -104,7 +110,7 @@ public: | |||
| 104 | const std::array<GCState, 4>& GetPadState() const; | 110 | const std::array<GCState, 4>& GetPadState() const; |
| 105 | 111 | ||
| 106 | private: | 112 | private: |
| 107 | GCPadStatus GetPadStatus(int port, const std::array<u8, 37>& adapter_payload); | 113 | GCPadStatus GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload); |
| 108 | 114 | ||
| 109 | void PadToState(const GCPadStatus& pad, GCState& state); | 115 | void PadToState(const GCPadStatus& pad, GCState& state); |
| 110 | 116 | ||
| @@ -116,11 +122,8 @@ private: | |||
| 116 | /// Stop scanning for the adapter | 122 | /// Stop scanning for the adapter |
| 117 | void StopScanThread(); | 123 | void StopScanThread(); |
| 118 | 124 | ||
| 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 | 125 | /// Resets status of device connected to port |
| 123 | void ResetDeviceType(int port); | 126 | void ResetDeviceType(std::size_t port); |
| 124 | 127 | ||
| 125 | /// Returns true if we successfully gain access to GC Adapter | 128 | /// Returns true if we successfully gain access to GC Adapter |
| 126 | bool CheckDeviceAccess(libusb_device* device); | 129 | bool CheckDeviceAccess(libusb_device* device); |
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp index 385ce8430..b20419ec3 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: |
| @@ -43,13 +47,17 @@ public: | |||
| 43 | } | 47 | } |
| 44 | 48 | ||
| 45 | bool GetStatus() const override { | 49 | bool GetStatus() const override { |
| 46 | const float axis_value = (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 128.0f; | 50 | if (gcadapter->DeviceConnected(port)) { |
| 47 | if (trigger_if_greater) { | 51 | const float axis_value = |
| 48 | // TODO: Might be worthwile to set a slider for the trigger threshold. It is currently | 52 | (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 128.0f; |
| 49 | // always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick | 53 | if (trigger_if_greater) { |
| 50 | return axis_value > threshold; | 54 | // TODO: Might be worthwile to set a slider for the trigger threshold. It is |
| 55 | // currently always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick | ||
| 56 | return axis_value > threshold; | ||
| 57 | } | ||
| 58 | return axis_value < -threshold; | ||
| 51 | } | 59 | } |
| 52 | return axis_value < -threshold; | 60 | return false; |
| 53 | } | 61 | } |
| 54 | 62 | ||
| 55 | private: | 63 | private: |
| @@ -94,9 +102,12 @@ std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::Param | |||
| 94 | return std::make_unique<GCAxisButton>(port, axis, threshold, trigger_if_greater, | 102 | return std::make_unique<GCAxisButton>(port, axis, threshold, trigger_if_greater, |
| 95 | adapter.get()); | 103 | adapter.get()); |
| 96 | } | 104 | } |
| 105 | |||
| 106 | UNREACHABLE(); | ||
| 107 | return nullptr; | ||
| 97 | } | 108 | } |
| 98 | 109 | ||
| 99 | Common::ParamPackage GCButtonFactory::GetNextInput() { | 110 | Common::ParamPackage GCButtonFactory::GetNextInput() const { |
| 100 | Common::ParamPackage params; | 111 | Common::ParamPackage params; |
| 101 | GCAdapter::GCPadStatus pad; | 112 | GCAdapter::GCPadStatus pad; |
| 102 | auto& queue = adapter->GetPadQueue(); | 113 | auto& queue = adapter->GetPadQueue(); |
| @@ -147,11 +158,14 @@ public: | |||
| 147 | : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter) {} | 158 | : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter) {} |
| 148 | 159 | ||
| 149 | float GetAxis(int axis) const { | 160 | float GetAxis(int axis) const { |
| 150 | std::lock_guard lock{mutex}; | 161 | if (gcadapter->DeviceConnected(port)) { |
| 151 | // division is not by a perfect 128 to account for some variance in center location | 162 | 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 | 163 | // division is not by a perfect 128 to account for some variance in center location |
| 153 | // [20-230] | 164 | // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range |
| 154 | return (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 95.0f; | 165 | // [20-230] |
| 166 | return (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 95.0f; | ||
| 167 | } | ||
| 168 | return 0.0f; | ||
| 155 | } | 169 | } |
| 156 | 170 | ||
| 157 | std::pair<float, float> GetAnalog(int axis_x, int axis_y) const { | 171 | std::pair<float, float> GetAnalog(int axis_x, int axis_y) const { |
| @@ -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/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..9e9b38214 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 | ||
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_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 |