diff options
54 files changed, 796 insertions, 384 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index c6fc5dd9e..1d13dc74e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -133,13 +133,13 @@ if (NOT ENABLE_GENERIC) | |||
| 133 | if (MSVC) | 133 | if (MSVC) |
| 134 | detect_architecture("_M_AMD64" x86_64) | 134 | detect_architecture("_M_AMD64" x86_64) |
| 135 | detect_architecture("_M_IX86" x86) | 135 | detect_architecture("_M_IX86" x86) |
| 136 | detect_architecture("_M_ARM" ARM) | 136 | detect_architecture("_M_ARM" arm) |
| 137 | detect_architecture("_M_ARM64" ARM64) | 137 | detect_architecture("_M_ARM64" arm64) |
| 138 | else() | 138 | else() |
| 139 | detect_architecture("__x86_64__" x86_64) | 139 | detect_architecture("__x86_64__" x86_64) |
| 140 | detect_architecture("__i386__" x86) | 140 | detect_architecture("__i386__" x86) |
| 141 | detect_architecture("__arm__" ARM) | 141 | detect_architecture("__arm__" arm) |
| 142 | detect_architecture("__aarch64__" ARM64) | 142 | detect_architecture("__aarch64__" arm64) |
| 143 | endif() | 143 | endif() |
| 144 | endif() | 144 | endif() |
| 145 | 145 | ||
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index e80fd124e..7f0a6d069 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt | |||
| @@ -7,15 +7,14 @@ include(DownloadExternals) | |||
| 7 | 7 | ||
| 8 | # xbyak | 8 | # xbyak |
| 9 | if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) | 9 | if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) |
| 10 | add_library(xbyak INTERFACE) | 10 | add_subdirectory(xbyak) |
| 11 | file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/xbyak/include) | ||
| 12 | file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/xbyak/xbyak DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/xbyak/include) | ||
| 13 | target_include_directories(xbyak SYSTEM INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/xbyak/include) | ||
| 14 | target_compile_definitions(xbyak INTERFACE XBYAK_NO_OP_NAMES) | ||
| 15 | endif() | 11 | endif() |
| 16 | 12 | ||
| 17 | # Dynarmic | 13 | # Dynarmic |
| 18 | if (ARCHITECTURE_x86_64) | 14 | if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) |
| 15 | if (ARCHITECTURE_arm64) | ||
| 16 | set(DYNARMIC_FRONTENDS "A32") | ||
| 17 | endif() | ||
| 19 | set(DYNARMIC_NO_BUNDLED_FMT ON) | 18 | set(DYNARMIC_NO_BUNDLED_FMT ON) |
| 20 | set(DYNARMIC_IGNORE_ASSERTS ON CACHE BOOL "" FORCE) | 19 | set(DYNARMIC_IGNORE_ASSERTS ON CACHE BOOL "" FORCE) |
| 21 | add_subdirectory(dynarmic) | 20 | add_subdirectory(dynarmic) |
diff --git a/externals/dynarmic b/externals/dynarmic | |||
| Subproject 2d4602a6516c67d547000d4c80bcc5f74976abd | Subproject 424fdb5c5026ec5bdd7553271190397f63fb503 | ||
diff --git a/externals/xbyak b/externals/xbyak | |||
| Subproject c306b8e5786eeeb87b8925a8af5c3bf057ff5a9 | Subproject 348e3e548ebac06d243e5881caec8440e249f65 | ||
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index 0a1f3bf18..8e3a8f5a8 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt | |||
| @@ -217,7 +217,7 @@ else() | |||
| 217 | endif() | 217 | endif() |
| 218 | 218 | ||
| 219 | target_link_libraries(audio_core PUBLIC common core) | 219 | target_link_libraries(audio_core PUBLIC common core) |
| 220 | if (ARCHITECTURE_x86_64) | 220 | if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) |
| 221 | target_link_libraries(audio_core PRIVATE dynarmic) | 221 | target_link_libraries(audio_core PRIVATE dynarmic) |
| 222 | endif() | 222 | endif() |
| 223 | 223 | ||
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index e1e2a90fc..0dad9338a 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h | |||
| @@ -31,8 +31,10 @@ | |||
| 31 | 31 | ||
| 32 | #ifndef _MSC_VER | 32 | #ifndef _MSC_VER |
| 33 | 33 | ||
| 34 | #ifdef ARCHITECTURE_x86_64 | 34 | #if defined(ARCHITECTURE_x86_64) |
| 35 | #define Crash() __asm__ __volatile__("int $3") | 35 | #define Crash() __asm__ __volatile__("int $3") |
| 36 | #elif defined(ARCHITECTURE_arm64) | ||
| 37 | #define Crash() __asm__ __volatile__("brk #0") | ||
| 36 | #else | 38 | #else |
| 37 | #define Crash() exit(1) | 39 | #define Crash() exit(1) |
| 38 | #endif | 40 | #endif |
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 7f9659612..909f6cf3f 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp | |||
| @@ -359,6 +359,12 @@ public: | |||
| 359 | } | 359 | } |
| 360 | }); | 360 | }); |
| 361 | 361 | ||
| 362 | long page_size = sysconf(_SC_PAGESIZE); | ||
| 363 | if (page_size != 0x1000) { | ||
| 364 | LOG_CRITICAL(HW_Memory, "page size {:#x} is incompatible with 4K paging", page_size); | ||
| 365 | throw std::bad_alloc{}; | ||
| 366 | } | ||
| 367 | |||
| 362 | // Backing memory initialization | 368 | // Backing memory initialization |
| 363 | #if defined(__FreeBSD__) && __FreeBSD__ < 13 | 369 | #if defined(__FreeBSD__) && __FreeBSD__ < 13 |
| 364 | // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30 | 370 | // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30 |
diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 0a560ebb7..8173462cb 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp | |||
| @@ -151,6 +151,7 @@ void UpdateRescalingInfo() { | |||
| 151 | ASSERT(false); | 151 | ASSERT(false); |
| 152 | info.up_scale = 1; | 152 | info.up_scale = 1; |
| 153 | info.down_shift = 0; | 153 | info.down_shift = 0; |
| 154 | break; | ||
| 154 | } | 155 | } |
| 155 | info.up_factor = static_cast<f32>(info.up_scale) / (1U << info.down_shift); | 156 | info.up_factor = static_cast<f32>(info.up_scale) / (1U << info.down_shift); |
| 156 | info.down_factor = static_cast<f32>(1U << info.down_shift) / info.up_scale; | 157 | info.down_factor = static_cast<f32>(1U << info.down_shift) / info.up_scale; |
diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp index 1a27532d4..e54383a4a 100644 --- a/src/common/x64/cpu_detect.cpp +++ b/src/common/x64/cpu_detect.cpp | |||
| @@ -4,14 +4,27 @@ | |||
| 4 | 4 | ||
| 5 | #include <array> | 5 | #include <array> |
| 6 | #include <cstring> | 6 | #include <cstring> |
| 7 | #include <fstream> | ||
| 7 | #include <iterator> | 8 | #include <iterator> |
| 9 | #include <optional> | ||
| 8 | #include <string_view> | 10 | #include <string_view> |
| 11 | #include <thread> | ||
| 12 | #include <vector> | ||
| 9 | #include "common/bit_util.h" | 13 | #include "common/bit_util.h" |
| 10 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| 15 | #include "common/logging/log.h" | ||
| 11 | #include "common/x64/cpu_detect.h" | 16 | #include "common/x64/cpu_detect.h" |
| 12 | 17 | ||
| 18 | #ifdef _WIN32 | ||
| 19 | #include <windows.h> | ||
| 20 | #endif | ||
| 21 | |||
| 13 | #ifdef _MSC_VER | 22 | #ifdef _MSC_VER |
| 14 | #include <intrin.h> | 23 | #include <intrin.h> |
| 24 | |||
| 25 | static inline u64 xgetbv(u32 index) { | ||
| 26 | return _xgetbv(index); | ||
| 27 | } | ||
| 15 | #else | 28 | #else |
| 16 | 29 | ||
| 17 | #if defined(__DragonFly__) || defined(__FreeBSD__) | 30 | #if defined(__DragonFly__) || defined(__FreeBSD__) |
| @@ -39,12 +52,11 @@ static inline void __cpuid(int info[4], u32 function_id) { | |||
| 39 | } | 52 | } |
| 40 | 53 | ||
| 41 | #define _XCR_XFEATURE_ENABLED_MASK 0 | 54 | #define _XCR_XFEATURE_ENABLED_MASK 0 |
| 42 | static inline u64 _xgetbv(u32 index) { | 55 | static inline u64 xgetbv(u32 index) { |
| 43 | u32 eax, edx; | 56 | u32 eax, edx; |
| 44 | __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index)); | 57 | __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index)); |
| 45 | return ((u64)edx << 32) | eax; | 58 | return ((u64)edx << 32) | eax; |
| 46 | } | 59 | } |
| 47 | |||
| 48 | #endif // _MSC_VER | 60 | #endif // _MSC_VER |
| 49 | 61 | ||
| 50 | namespace Common { | 62 | namespace Common { |
| @@ -107,7 +119,7 @@ static CPUCaps Detect() { | |||
| 107 | // - Is the XSAVE bit set in CPUID? | 119 | // - Is the XSAVE bit set in CPUID? |
| 108 | // - XGETBV result has the XCR bit set. | 120 | // - XGETBV result has the XCR bit set. |
| 109 | if (Common::Bit<28>(cpu_id[2]) && Common::Bit<27>(cpu_id[2])) { | 121 | if (Common::Bit<28>(cpu_id[2]) && Common::Bit<27>(cpu_id[2])) { |
| 110 | if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) { | 122 | if ((xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) { |
| 111 | caps.avx = true; | 123 | caps.avx = true; |
| 112 | if (Common::Bit<12>(cpu_id[2])) | 124 | if (Common::Bit<12>(cpu_id[2])) |
| 113 | caps.fma = true; | 125 | caps.fma = true; |
| @@ -192,4 +204,45 @@ const CPUCaps& GetCPUCaps() { | |||
| 192 | return caps; | 204 | return caps; |
| 193 | } | 205 | } |
| 194 | 206 | ||
| 207 | std::optional<int> GetProcessorCount() { | ||
| 208 | #if defined(_WIN32) | ||
| 209 | // Get the buffer length. | ||
| 210 | DWORD length = 0; | ||
| 211 | GetLogicalProcessorInformation(nullptr, &length); | ||
| 212 | if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { | ||
| 213 | LOG_ERROR(Frontend, "Failed to query core count."); | ||
| 214 | return std::nullopt; | ||
| 215 | } | ||
| 216 | std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer( | ||
| 217 | length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION)); | ||
| 218 | // Now query the core count. | ||
| 219 | if (!GetLogicalProcessorInformation(buffer.data(), &length)) { | ||
| 220 | LOG_ERROR(Frontend, "Failed to query core count."); | ||
| 221 | return std::nullopt; | ||
| 222 | } | ||
| 223 | return static_cast<int>( | ||
| 224 | std::count_if(buffer.cbegin(), buffer.cend(), [](const auto& proc_info) { | ||
| 225 | return proc_info.Relationship == RelationProcessorCore; | ||
| 226 | })); | ||
| 227 | #elif defined(__unix__) | ||
| 228 | const int thread_count = std::thread::hardware_concurrency(); | ||
| 229 | std::ifstream smt("/sys/devices/system/cpu/smt/active"); | ||
| 230 | char state = '0'; | ||
| 231 | if (smt) { | ||
| 232 | smt.read(&state, sizeof(state)); | ||
| 233 | } | ||
| 234 | switch (state) { | ||
| 235 | case '0': | ||
| 236 | return thread_count; | ||
| 237 | case '1': | ||
| 238 | return thread_count / 2; | ||
| 239 | default: | ||
| 240 | return std::nullopt; | ||
| 241 | } | ||
| 242 | #else | ||
| 243 | // Shame on you | ||
| 244 | return std::nullopt; | ||
| 245 | #endif | ||
| 246 | } | ||
| 247 | |||
| 195 | } // namespace Common | 248 | } // namespace Common |
diff --git a/src/common/x64/cpu_detect.h b/src/common/x64/cpu_detect.h index 6830f3795..ca8db19d6 100644 --- a/src/common/x64/cpu_detect.h +++ b/src/common/x64/cpu_detect.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <optional> | ||
| 7 | #include <string_view> | 8 | #include <string_view> |
| 8 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 9 | 10 | ||
| @@ -74,4 +75,7 @@ struct CPUCaps { | |||
| 74 | */ | 75 | */ |
| 75 | const CPUCaps& GetCPUCaps(); | 76 | const CPUCaps& GetCPUCaps(); |
| 76 | 77 | ||
| 78 | /// Detects CPU core count | ||
| 79 | std::optional<int> GetProcessorCount(); | ||
| 80 | |||
| 77 | } // namespace Common | 81 | } // namespace Common |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f6e082c36..f67f1ce92 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -497,10 +497,6 @@ add_library(core STATIC | |||
| 497 | hle/service/hid/irsensor/processor_base.h | 497 | hle/service/hid/irsensor/processor_base.h |
| 498 | hle/service/hid/irsensor/tera_plugin_processor.cpp | 498 | hle/service/hid/irsensor/tera_plugin_processor.cpp |
| 499 | hle/service/hid/irsensor/tera_plugin_processor.h | 499 | hle/service/hid/irsensor/tera_plugin_processor.h |
| 500 | hle/service/jit/jit_context.cpp | ||
| 501 | hle/service/jit/jit_context.h | ||
| 502 | hle/service/jit/jit.cpp | ||
| 503 | hle/service/jit/jit.h | ||
| 504 | hle/service/lbl/lbl.cpp | 500 | hle/service/lbl/lbl.cpp |
| 505 | hle/service/lbl/lbl.h | 501 | hle/service/lbl/lbl.h |
| 506 | hle/service/ldn/lan_discovery.cpp | 502 | hle/service/ldn/lan_discovery.cpp |
| @@ -805,14 +801,18 @@ if (ENABLE_WEB_SERVICE) | |||
| 805 | target_link_libraries(core PRIVATE web_service) | 801 | target_link_libraries(core PRIVATE web_service) |
| 806 | endif() | 802 | endif() |
| 807 | 803 | ||
| 808 | if (ARCHITECTURE_x86_64) | 804 | if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) |
| 809 | target_sources(core PRIVATE | 805 | target_sources(core PRIVATE |
| 810 | arm/dynarmic/arm_dynarmic_32.cpp | ||
| 811 | arm/dynarmic/arm_dynarmic_32.h | ||
| 812 | arm/dynarmic/arm_dynarmic_64.cpp | 806 | arm/dynarmic/arm_dynarmic_64.cpp |
| 813 | arm/dynarmic/arm_dynarmic_64.h | 807 | arm/dynarmic/arm_dynarmic_64.h |
| 808 | arm/dynarmic/arm_dynarmic_32.cpp | ||
| 809 | arm/dynarmic/arm_dynarmic_32.h | ||
| 814 | arm/dynarmic/arm_dynarmic_cp15.cpp | 810 | arm/dynarmic/arm_dynarmic_cp15.cpp |
| 815 | arm/dynarmic/arm_dynarmic_cp15.h | 811 | arm/dynarmic/arm_dynarmic_cp15.h |
| 812 | hle/service/jit/jit_context.cpp | ||
| 813 | hle/service/jit/jit_context.h | ||
| 814 | hle/service/jit/jit.cpp | ||
| 815 | hle/service/jit/jit.h | ||
| 816 | ) | 816 | ) |
| 817 | target_link_libraries(core PRIVATE dynarmic) | 817 | target_link_libraries(core PRIVATE dynarmic) |
| 818 | endif() | 818 | endif() |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 287ba102e..227e06ea1 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp | |||
| @@ -301,6 +301,11 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* | |||
| 301 | } | 301 | } |
| 302 | } | 302 | } |
| 303 | 303 | ||
| 304 | #ifdef ARCHITECTURE_arm64 | ||
| 305 | // TODO: remove when fixed in dynarmic | ||
| 306 | config.optimizations &= ~Dynarmic::OptimizationFlag::BlockLinking; | ||
| 307 | #endif | ||
| 308 | |||
| 304 | return std::make_unique<Dynarmic::A32::Jit>(config); | 309 | return std::make_unique<Dynarmic::A32::Jit>(config); |
| 305 | } | 310 | } |
| 306 | 311 | ||
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp index 200efe4db..5a4eba3eb 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp | |||
| @@ -52,12 +52,16 @@ CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1 | |||
| 52 | case 4: | 52 | case 4: |
| 53 | // CP15_DATA_SYNC_BARRIER | 53 | // CP15_DATA_SYNC_BARRIER |
| 54 | return Callback{ | 54 | return Callback{ |
| 55 | [](Dynarmic::A32::Jit*, void*, std::uint32_t, std::uint32_t) -> std::uint64_t { | 55 | [](void*, std::uint32_t, std::uint32_t) -> std::uint64_t { |
| 56 | #ifdef _MSC_VER | 56 | #if defined(_MSC_VER) && defined(ARCHITECTURE_x86_64) |
| 57 | _mm_mfence(); | 57 | _mm_mfence(); |
| 58 | _mm_lfence(); | 58 | _mm_lfence(); |
| 59 | #else | 59 | #elif defined(ARCHITECTURE_x86_64) |
| 60 | asm volatile("mfence\n\tlfence\n\t" : : : "memory"); | 60 | asm volatile("mfence\n\tlfence\n\t" : : : "memory"); |
| 61 | #elif defined(ARCHITECTURE_arm64) | ||
| 62 | asm volatile("dsb sy\n\t" : : : "memory"); | ||
| 63 | #else | ||
| 64 | #error Unsupported architecture | ||
| 61 | #endif | 65 | #endif |
| 62 | return 0; | 66 | return 0; |
| 63 | }, | 67 | }, |
| @@ -66,11 +70,15 @@ CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1 | |||
| 66 | case 5: | 70 | case 5: |
| 67 | // CP15_DATA_MEMORY_BARRIER | 71 | // CP15_DATA_MEMORY_BARRIER |
| 68 | return Callback{ | 72 | return Callback{ |
| 69 | [](Dynarmic::A32::Jit*, void*, std::uint32_t, std::uint32_t) -> std::uint64_t { | 73 | [](void*, std::uint32_t, std::uint32_t) -> std::uint64_t { |
| 70 | #ifdef _MSC_VER | 74 | #if defined(_MSC_VER) && defined(ARCHITECTURE_x86_64) |
| 71 | _mm_mfence(); | 75 | _mm_mfence(); |
| 72 | #else | 76 | #elif defined(ARCHITECTURE_x86_64) |
| 73 | asm volatile("mfence\n\t" : : : "memory"); | 77 | asm volatile("mfence\n\t" : : : "memory"); |
| 78 | #elif defined(ARCHITECTURE_arm64) | ||
| 79 | asm volatile("dmb sy\n\t" : : : "memory"); | ||
| 80 | #else | ||
| 81 | #error Unsupported architecture | ||
| 74 | #endif | 82 | #endif |
| 75 | return 0; | 83 | return 0; |
| 76 | }, | 84 | }, |
| @@ -115,7 +123,7 @@ CallbackOrAccessOneWord DynarmicCP15::CompileGetOneWord(bool two, unsigned opc1, | |||
| 115 | CallbackOrAccessTwoWords DynarmicCP15::CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) { | 123 | CallbackOrAccessTwoWords DynarmicCP15::CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) { |
| 116 | if (!two && opc == 0 && CRm == CoprocReg::C14) { | 124 | if (!two && opc == 0 && CRm == CoprocReg::C14) { |
| 117 | // CNTPCT | 125 | // CNTPCT |
| 118 | const auto callback = [](Dynarmic::A32::Jit*, void* arg, u32, u32) -> u64 { | 126 | const auto callback = [](void* arg, u32, u32) -> u64 { |
| 119 | const auto& parent_arg = *static_cast<ARM_Dynarmic_32*>(arg); | 127 | const auto& parent_arg = *static_cast<ARM_Dynarmic_32*>(arg); |
| 120 | return parent_arg.system.CoreTiming().GetClockTicks(); | 128 | return parent_arg.system.CoreTiming().GetClockTicks(); |
| 121 | }; | 129 | }; |
diff --git a/src/core/arm/exclusive_monitor.cpp b/src/core/arm/exclusive_monitor.cpp index 2db0b035d..20550faeb 100644 --- a/src/core/arm/exclusive_monitor.cpp +++ b/src/core/arm/exclusive_monitor.cpp | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #ifdef ARCHITECTURE_x86_64 | 4 | #if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64) |
| 5 | #include "core/arm/dynarmic/arm_exclusive_monitor.h" | 5 | #include "core/arm/dynarmic/arm_exclusive_monitor.h" |
| 6 | #endif | 6 | #endif |
| 7 | #include "core/arm/exclusive_monitor.h" | 7 | #include "core/arm/exclusive_monitor.h" |
| @@ -13,7 +13,7 @@ ExclusiveMonitor::~ExclusiveMonitor() = default; | |||
| 13 | 13 | ||
| 14 | std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory, | 14 | std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory, |
| 15 | std::size_t num_cores) { | 15 | std::size_t num_cores) { |
| 16 | #ifdef ARCHITECTURE_x86_64 | 16 | #if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64) |
| 17 | return std::make_unique<Core::DynarmicExclusiveMonitor>(memory, num_cores); | 17 | return std::make_unique<Core::DynarmicExclusiveMonitor>(memory, num_cores); |
| 18 | #else | 18 | #else |
| 19 | // TODO(merry): Passthrough exclusive monitor | 19 | // TODO(merry): Passthrough exclusive monitor |
diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index d4375962f..3044922ac 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp | |||
| @@ -12,7 +12,7 @@ namespace Kernel { | |||
| 12 | 12 | ||
| 13 | PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_) | 13 | PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_) |
| 14 | : core_index{core_index_}, system{system_}, scheduler{scheduler_} { | 14 | : core_index{core_index_}, system{system_}, scheduler{scheduler_} { |
| 15 | #ifdef ARCHITECTURE_x86_64 | 15 | #if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64) |
| 16 | // TODO(bunnei): Initialization relies on a core being available. We may later replace this with | 16 | // TODO(bunnei): Initialization relies on a core being available. We may later replace this with |
| 17 | // a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager. | 17 | // a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager. |
| 18 | auto& kernel = system.Kernel(); | 18 | auto& kernel = system.Kernel(); |
| @@ -26,7 +26,7 @@ PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KSche | |||
| 26 | PhysicalCore::~PhysicalCore() = default; | 26 | PhysicalCore::~PhysicalCore() = default; |
| 27 | 27 | ||
| 28 | void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) { | 28 | void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) { |
| 29 | #ifdef ARCHITECTURE_x86_64 | 29 | #if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64) |
| 30 | auto& kernel = system.Kernel(); | 30 | auto& kernel = system.Kernel(); |
| 31 | if (!is_64_bit) { | 31 | if (!is_64_bit) { |
| 32 | // We already initialized a 64-bit core, replace with a 32-bit one. | 32 | // We already initialized a 64-bit core, replace with a 32-bit one. |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp index 0a7d42dda..d6562c842 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp | |||
| @@ -379,6 +379,18 @@ void EmitInvocationId(EmitContext& ctx, IR::Inst& inst) { | |||
| 379 | ctx.Add("MOV.S {}.x,primitive_invocation.x;", inst); | 379 | ctx.Add("MOV.S {}.x,primitive_invocation.x;", inst); |
| 380 | } | 380 | } |
| 381 | 381 | ||
| 382 | void EmitInvocationInfo(EmitContext& ctx, IR::Inst& inst) { | ||
| 383 | switch (ctx.stage) { | ||
| 384 | case Stage::TessellationControl: | ||
| 385 | case Stage::TessellationEval: | ||
| 386 | ctx.Add("SHL.U {}.x,primitive.vertexcount,16;", inst); | ||
| 387 | break; | ||
| 388 | default: | ||
| 389 | LOG_WARNING(Shader, "(STUBBED) called"); | ||
| 390 | ctx.Add("MOV.S {}.x,0x00ff0000;", inst); | ||
| 391 | } | ||
| 392 | } | ||
| 393 | |||
| 382 | void EmitSampleId(EmitContext& ctx, IR::Inst& inst) { | 394 | void EmitSampleId(EmitContext& ctx, IR::Inst& inst) { |
| 383 | ctx.Add("MOV.S {}.x,fragment.sampleid.x;", inst); | 395 | ctx.Add("MOV.S {}.x,fragment.sampleid.x;", inst); |
| 384 | } | 396 | } |
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h index d645fd532..eaaf9ba39 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h +++ b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h | |||
| @@ -69,6 +69,7 @@ void EmitSetOFlag(EmitContext& ctx); | |||
| 69 | void EmitWorkgroupId(EmitContext& ctx, IR::Inst& inst); | 69 | void EmitWorkgroupId(EmitContext& ctx, IR::Inst& inst); |
| 70 | void EmitLocalInvocationId(EmitContext& ctx, IR::Inst& inst); | 70 | void EmitLocalInvocationId(EmitContext& ctx, IR::Inst& inst); |
| 71 | void EmitInvocationId(EmitContext& ctx, IR::Inst& inst); | 71 | void EmitInvocationId(EmitContext& ctx, IR::Inst& inst); |
| 72 | void EmitInvocationInfo(EmitContext& ctx, IR::Inst& inst); | ||
| 72 | void EmitSampleId(EmitContext& ctx, IR::Inst& inst); | 73 | void EmitSampleId(EmitContext& ctx, IR::Inst& inst); |
| 73 | void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst); | 74 | void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst); |
| 74 | void EmitYDirection(EmitContext& ctx, IR::Inst& inst); | 75 | void EmitYDirection(EmitContext& ctx, IR::Inst& inst); |
diff --git a/src/shader_recompiler/backend/glasm/glasm_emit_context.cpp b/src/shader_recompiler/backend/glasm/glasm_emit_context.cpp index 89603c1c4..333a91cc5 100644 --- a/src/shader_recompiler/backend/glasm/glasm_emit_context.cpp +++ b/src/shader_recompiler/backend/glasm/glasm_emit_context.cpp | |||
| @@ -95,6 +95,10 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile | |||
| 95 | if (info.uses_invocation_id) { | 95 | if (info.uses_invocation_id) { |
| 96 | Add("ATTRIB primitive_invocation=primitive.invocation;"); | 96 | Add("ATTRIB primitive_invocation=primitive.invocation;"); |
| 97 | } | 97 | } |
| 98 | if (info.uses_invocation_info && | ||
| 99 | (stage == Stage::TessellationControl || stage == Stage::TessellationEval)) { | ||
| 100 | Add("ATTRIB primitive_vertexcount = primitive.vertexcount;"); | ||
| 101 | } | ||
| 98 | if (info.stores_tess_level_outer) { | 102 | if (info.stores_tess_level_outer) { |
| 99 | Add("OUTPUT result_patch_tessouter[]={{result.patch.tessouter[0..3]}};"); | 103 | Add("OUTPUT result_patch_tessouter[]={{result.patch.tessouter[0..3]}};"); |
| 100 | } | 104 | } |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp index d7c845469..c1671c37b 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp | |||
| @@ -399,6 +399,18 @@ void EmitInvocationId(EmitContext& ctx, IR::Inst& inst) { | |||
| 399 | ctx.AddU32("{}=uint(gl_InvocationID);", inst); | 399 | ctx.AddU32("{}=uint(gl_InvocationID);", inst); |
| 400 | } | 400 | } |
| 401 | 401 | ||
| 402 | void EmitInvocationInfo(EmitContext& ctx, IR::Inst& inst) { | ||
| 403 | switch (ctx.stage) { | ||
| 404 | case Stage::TessellationControl: | ||
| 405 | case Stage::TessellationEval: | ||
| 406 | ctx.AddU32("{}=uint(gl_PatchVerticesIn)<<16;", inst); | ||
| 407 | break; | ||
| 408 | default: | ||
| 409 | LOG_WARNING(Shader, "(STUBBED) called"); | ||
| 410 | ctx.AddU32("{}=uint(0x00ff0000);", inst); | ||
| 411 | } | ||
| 412 | } | ||
| 413 | |||
| 402 | void EmitSampleId(EmitContext& ctx, IR::Inst& inst) { | 414 | void EmitSampleId(EmitContext& ctx, IR::Inst& inst) { |
| 403 | ctx.AddU32("{}=uint(gl_SampleID);", inst); | 415 | ctx.AddU32("{}=uint(gl_SampleID);", inst); |
| 404 | } | 416 | } |
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h index 96e683b5e..4151c89de 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h +++ b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h | |||
| @@ -83,6 +83,7 @@ void EmitSetOFlag(EmitContext& ctx); | |||
| 83 | void EmitWorkgroupId(EmitContext& ctx, IR::Inst& inst); | 83 | void EmitWorkgroupId(EmitContext& ctx, IR::Inst& inst); |
| 84 | void EmitLocalInvocationId(EmitContext& ctx, IR::Inst& inst); | 84 | void EmitLocalInvocationId(EmitContext& ctx, IR::Inst& inst); |
| 85 | void EmitInvocationId(EmitContext& ctx, IR::Inst& inst); | 85 | void EmitInvocationId(EmitContext& ctx, IR::Inst& inst); |
| 86 | void EmitInvocationInfo(EmitContext& ctx, IR::Inst& inst); | ||
| 86 | void EmitSampleId(EmitContext& ctx, IR::Inst& inst); | 87 | void EmitSampleId(EmitContext& ctx, IR::Inst& inst); |
| 87 | void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst); | 88 | void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst); |
| 88 | void EmitYDirection(EmitContext& ctx, IR::Inst& inst); | 89 | void EmitYDirection(EmitContext& ctx, IR::Inst& inst); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp index a4751b42d..5b3b5d1f3 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp | |||
| @@ -512,6 +512,18 @@ Id EmitInvocationId(EmitContext& ctx) { | |||
| 512 | return ctx.OpLoad(ctx.U32[1], ctx.invocation_id); | 512 | return ctx.OpLoad(ctx.U32[1], ctx.invocation_id); |
| 513 | } | 513 | } |
| 514 | 514 | ||
| 515 | Id EmitInvocationInfo(EmitContext& ctx) { | ||
| 516 | switch (ctx.stage) { | ||
| 517 | case Stage::TessellationControl: | ||
| 518 | case Stage::TessellationEval: | ||
| 519 | return ctx.OpShiftLeftLogical(ctx.U32[1], ctx.OpLoad(ctx.U32[1], ctx.patch_vertices_in), | ||
| 520 | ctx.Const(16u)); | ||
| 521 | default: | ||
| 522 | LOG_WARNING(Shader, "(STUBBED) called"); | ||
| 523 | return ctx.Const(0x00ff0000u); | ||
| 524 | } | ||
| 525 | } | ||
| 526 | |||
| 515 | Id EmitSampleId(EmitContext& ctx) { | 527 | Id EmitSampleId(EmitContext& ctx) { |
| 516 | return ctx.OpLoad(ctx.U32[1], ctx.sample_id); | 528 | return ctx.OpLoad(ctx.U32[1], ctx.sample_id); |
| 517 | } | 529 | } |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 7070c8fda..e31cdc5e8 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h | |||
| @@ -72,6 +72,7 @@ void EmitSetOFlag(EmitContext& ctx); | |||
| 72 | Id EmitWorkgroupId(EmitContext& ctx); | 72 | Id EmitWorkgroupId(EmitContext& ctx); |
| 73 | Id EmitLocalInvocationId(EmitContext& ctx); | 73 | Id EmitLocalInvocationId(EmitContext& ctx); |
| 74 | Id EmitInvocationId(EmitContext& ctx); | 74 | Id EmitInvocationId(EmitContext& ctx); |
| 75 | Id EmitInvocationInfo(EmitContext& ctx); | ||
| 75 | Id EmitSampleId(EmitContext& ctx); | 76 | Id EmitSampleId(EmitContext& ctx); |
| 76 | Id EmitIsHelperInvocation(EmitContext& ctx); | 77 | Id EmitIsHelperInvocation(EmitContext& ctx); |
| 77 | Id EmitYDirection(EmitContext& ctx); | 78 | Id EmitYDirection(EmitContext& ctx); |
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index c26ad8f93..0bfc2dd89 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp | |||
| @@ -1325,6 +1325,10 @@ void EmitContext::DefineInputs(const IR::Program& program) { | |||
| 1325 | if (info.uses_invocation_id) { | 1325 | if (info.uses_invocation_id) { |
| 1326 | invocation_id = DefineInput(*this, U32[1], false, spv::BuiltIn::InvocationId); | 1326 | invocation_id = DefineInput(*this, U32[1], false, spv::BuiltIn::InvocationId); |
| 1327 | } | 1327 | } |
| 1328 | if (info.uses_invocation_info && | ||
| 1329 | (stage == Shader::Stage::TessellationControl || stage == Shader::Stage::TessellationEval)) { | ||
| 1330 | patch_vertices_in = DefineInput(*this, U32[1], false, spv::BuiltIn::PatchVertices); | ||
| 1331 | } | ||
| 1328 | if (info.uses_sample_id) { | 1332 | if (info.uses_sample_id) { |
| 1329 | sample_id = DefineInput(*this, U32[1], false, spv::BuiltIn::SampleId); | 1333 | sample_id = DefineInput(*this, U32[1], false, spv::BuiltIn::SampleId); |
| 1330 | } | 1334 | } |
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index c86e50911..dde45b4bc 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h | |||
| @@ -204,6 +204,7 @@ public: | |||
| 204 | Id workgroup_id{}; | 204 | Id workgroup_id{}; |
| 205 | Id local_invocation_id{}; | 205 | Id local_invocation_id{}; |
| 206 | Id invocation_id{}; | 206 | Id invocation_id{}; |
| 207 | Id patch_vertices_in{}; | ||
| 207 | Id sample_id{}; | 208 | Id sample_id{}; |
| 208 | Id is_helper_invocation{}; | 209 | Id is_helper_invocation{}; |
| 209 | Id subgroup_local_invocation_id{}; | 210 | Id subgroup_local_invocation_id{}; |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index d4425f06d..0cdac0eff 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp | |||
| @@ -362,6 +362,10 @@ U32 IREmitter::InvocationId() { | |||
| 362 | return Inst<U32>(Opcode::InvocationId); | 362 | return Inst<U32>(Opcode::InvocationId); |
| 363 | } | 363 | } |
| 364 | 364 | ||
| 365 | U32 IREmitter::InvocationInfo() { | ||
| 366 | return Inst<U32>(Opcode::InvocationInfo); | ||
| 367 | } | ||
| 368 | |||
| 365 | U32 IREmitter::SampleId() { | 369 | U32 IREmitter::SampleId() { |
| 366 | return Inst<U32>(Opcode::SampleId); | 370 | return Inst<U32>(Opcode::SampleId); |
| 367 | } | 371 | } |
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index f163c18d9..2df992feb 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h | |||
| @@ -97,6 +97,7 @@ public: | |||
| 97 | [[nodiscard]] U32 LocalInvocationIdZ(); | 97 | [[nodiscard]] U32 LocalInvocationIdZ(); |
| 98 | 98 | ||
| 99 | [[nodiscard]] U32 InvocationId(); | 99 | [[nodiscard]] U32 InvocationId(); |
| 100 | [[nodiscard]] U32 InvocationInfo(); | ||
| 100 | [[nodiscard]] U32 SampleId(); | 101 | [[nodiscard]] U32 SampleId(); |
| 101 | [[nodiscard]] U1 IsHelperInvocation(); | 102 | [[nodiscard]] U1 IsHelperInvocation(); |
| 102 | [[nodiscard]] F32 YDirection(); | 103 | [[nodiscard]] F32 YDirection(); |
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index 88aa077ee..1fe3749cc 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc | |||
| @@ -59,6 +59,7 @@ OPCODE(SetOFlag, Void, U1, | |||
| 59 | OPCODE(WorkgroupId, U32x3, ) | 59 | OPCODE(WorkgroupId, U32x3, ) |
| 60 | OPCODE(LocalInvocationId, U32x3, ) | 60 | OPCODE(LocalInvocationId, U32x3, ) |
| 61 | OPCODE(InvocationId, U32, ) | 61 | OPCODE(InvocationId, U32, ) |
| 62 | OPCODE(InvocationInfo, U32, ) | ||
| 62 | OPCODE(SampleId, U32, ) | 63 | OPCODE(SampleId, U32, ) |
| 63 | OPCODE(IsHelperInvocation, U1, ) | 64 | OPCODE(IsHelperInvocation, U1, ) |
| 64 | OPCODE(YDirection, F32, ) | 65 | OPCODE(YDirection, F32, ) |
diff --git a/src/shader_recompiler/frontend/ir/patch.h b/src/shader_recompiler/frontend/ir/patch.h index 1e37c8eb6..5077e56c2 100644 --- a/src/shader_recompiler/frontend/ir/patch.h +++ b/src/shader_recompiler/frontend/ir/patch.h | |||
| @@ -14,8 +14,6 @@ enum class Patch : u64 { | |||
| 14 | TessellationLodBottom, | 14 | TessellationLodBottom, |
| 15 | TessellationLodInteriorU, | 15 | TessellationLodInteriorU, |
| 16 | TessellationLodInteriorV, | 16 | TessellationLodInteriorV, |
| 17 | ComponentPadding0, | ||
| 18 | ComponentPadding1, | ||
| 19 | Component0, | 17 | Component0, |
| 20 | Component1, | 18 | Component1, |
| 21 | Component2, | 19 | Component2, |
| @@ -137,7 +135,7 @@ enum class Patch : u64 { | |||
| 137 | Component118, | 135 | Component118, |
| 138 | Component119, | 136 | Component119, |
| 139 | }; | 137 | }; |
| 140 | static_assert(static_cast<u64>(Patch::Component119) == 127); | 138 | static_assert(static_cast<u64>(Patch::Component119) == 125); |
| 141 | 139 | ||
| 142 | [[nodiscard]] bool IsGeneric(Patch patch) noexcept; | 140 | [[nodiscard]] bool IsGeneric(Patch patch) noexcept; |
| 143 | 141 | ||
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/move_special_register.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/move_special_register.cpp index 52be12f9c..753c62098 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/move_special_register.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/move_special_register.cpp | |||
| @@ -117,8 +117,7 @@ enum class SpecialRegister : u64 { | |||
| 117 | case SpecialRegister::SR_THREAD_KILL: | 117 | case SpecialRegister::SR_THREAD_KILL: |
| 118 | return IR::U32{ir.Select(ir.IsHelperInvocation(), ir.Imm32(-1), ir.Imm32(0))}; | 118 | return IR::U32{ir.Select(ir.IsHelperInvocation(), ir.Imm32(-1), ir.Imm32(0))}; |
| 119 | case SpecialRegister::SR_INVOCATION_INFO: | 119 | case SpecialRegister::SR_INVOCATION_INFO: |
| 120 | LOG_WARNING(Shader, "(STUBBED) SR_INVOCATION_INFO"); | 120 | return ir.InvocationInfo(); |
| 121 | return ir.Imm32(0x00ff'0000); | ||
| 122 | case SpecialRegister::SR_TID: { | 121 | case SpecialRegister::SR_TID: { |
| 123 | const IR::Value tid{ir.LocalInvocationId()}; | 122 | const IR::Value tid{ir.LocalInvocationId()}; |
| 124 | return ir.BitFieldInsert(ir.BitFieldInsert(IR::U32{ir.CompositeExtract(tid, 0)}, | 123 | return ir.BitFieldInsert(ir.BitFieldInsert(IR::U32{ir.CompositeExtract(tid, 0)}, |
diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp index b7162f719..376aae0ea 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp | |||
| @@ -223,7 +223,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo | |||
| 223 | Optimization::PositionPass(env, program); | 223 | Optimization::PositionPass(env, program); |
| 224 | 224 | ||
| 225 | Optimization::GlobalMemoryToStorageBufferPass(program); | 225 | Optimization::GlobalMemoryToStorageBufferPass(program); |
| 226 | Optimization::TexturePass(env, program); | 226 | Optimization::TexturePass(env, program, host_info); |
| 227 | 227 | ||
| 228 | if (Settings::values.resolution_info.active) { | 228 | if (Settings::values.resolution_info.active) { |
| 229 | Optimization::RescalingPass(program); | 229 | Optimization::RescalingPass(program); |
diff --git a/src/shader_recompiler/host_translate_info.h b/src/shader_recompiler/host_translate_info.h index 881874310..cc1500690 100644 --- a/src/shader_recompiler/host_translate_info.h +++ b/src/shader_recompiler/host_translate_info.h | |||
| @@ -13,6 +13,7 @@ struct HostTranslateInfo { | |||
| 13 | bool support_float16{}; ///< True when the device supports 16-bit floats | 13 | bool support_float16{}; ///< True when the device supports 16-bit floats |
| 14 | bool support_int64{}; ///< True when the device supports 64-bit integers | 14 | bool support_int64{}; ///< True when the device supports 64-bit integers |
| 15 | bool needs_demote_reorder{}; ///< True when the device needs DemoteToHelperInvocation reordered | 15 | bool needs_demote_reorder{}; ///< True when the device needs DemoteToHelperInvocation reordered |
| 16 | bool support_snorm_render_buffer{}; ///< True when the device supports SNORM render buffers | ||
| 16 | }; | 17 | }; |
| 17 | 18 | ||
| 18 | } // namespace Shader | 19 | } // namespace Shader |
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp index 7cff8ecdc..5a4195217 100644 --- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp +++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp | |||
| @@ -468,6 +468,9 @@ void VisitUsages(Info& info, IR::Inst& inst) { | |||
| 468 | case IR::Opcode::InvocationId: | 468 | case IR::Opcode::InvocationId: |
| 469 | info.uses_invocation_id = true; | 469 | info.uses_invocation_id = true; |
| 470 | break; | 470 | break; |
| 471 | case IR::Opcode::InvocationInfo: | ||
| 472 | info.uses_invocation_info = true; | ||
| 473 | break; | ||
| 471 | case IR::Opcode::SampleId: | 474 | case IR::Opcode::SampleId: |
| 472 | info.uses_sample_id = true; | 475 | info.uses_sample_id = true; |
| 473 | break; | 476 | break; |
diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h index 24f609d69..586a0668f 100644 --- a/src/shader_recompiler/ir_opt/passes.h +++ b/src/shader_recompiler/ir_opt/passes.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | #include "shader_recompiler/environment.h" | 6 | #include "shader_recompiler/environment.h" |
| 7 | #include "shader_recompiler/frontend/ir/program.h" | 7 | #include "shader_recompiler/frontend/ir/program.h" |
| 8 | 8 | ||
| 9 | namespace Shader { | ||
| 10 | struct HostTranslateInfo; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Shader::Optimization { | 13 | namespace Shader::Optimization { |
| 10 | 14 | ||
| 11 | void CollectShaderInfoPass(Environment& env, IR::Program& program); | 15 | void CollectShaderInfoPass(Environment& env, IR::Program& program); |
| @@ -18,7 +22,7 @@ void LowerInt64ToInt32(IR::Program& program); | |||
| 18 | void RescalingPass(IR::Program& program); | 22 | void RescalingPass(IR::Program& program); |
| 19 | void SsaRewritePass(IR::Program& program); | 23 | void SsaRewritePass(IR::Program& program); |
| 20 | void PositionPass(Environment& env, IR::Program& program); | 24 | void PositionPass(Environment& env, IR::Program& program); |
| 21 | void TexturePass(Environment& env, IR::Program& program); | 25 | void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info); |
| 22 | void VerificationPass(const IR::Program& program); | 26 | void VerificationPass(const IR::Program& program); |
| 23 | 27 | ||
| 24 | // Dual Vertex | 28 | // Dual Vertex |
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp index 9eff84a3d..f5c86fcb1 100644 --- a/src/shader_recompiler/ir_opt/texture_pass.cpp +++ b/src/shader_recompiler/ir_opt/texture_pass.cpp | |||
| @@ -7,11 +7,11 @@ | |||
| 7 | 7 | ||
| 8 | #include <boost/container/small_vector.hpp> | 8 | #include <boost/container/small_vector.hpp> |
| 9 | 9 | ||
| 10 | #include "common/settings.h" | ||
| 11 | #include "shader_recompiler/environment.h" | 10 | #include "shader_recompiler/environment.h" |
| 12 | #include "shader_recompiler/frontend/ir/basic_block.h" | 11 | #include "shader_recompiler/frontend/ir/basic_block.h" |
| 13 | #include "shader_recompiler/frontend/ir/breadth_first_search.h" | 12 | #include "shader_recompiler/frontend/ir/breadth_first_search.h" |
| 14 | #include "shader_recompiler/frontend/ir/ir_emitter.h" | 13 | #include "shader_recompiler/frontend/ir/ir_emitter.h" |
| 14 | #include "shader_recompiler/host_translate_info.h" | ||
| 15 | #include "shader_recompiler/ir_opt/passes.h" | 15 | #include "shader_recompiler/ir_opt/passes.h" |
| 16 | #include "shader_recompiler/shader_info.h" | 16 | #include "shader_recompiler/shader_info.h" |
| 17 | 17 | ||
| @@ -461,7 +461,7 @@ void PatchImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) { | |||
| 461 | ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 1)))))); | 461 | ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 1)))))); |
| 462 | } | 462 | } |
| 463 | 463 | ||
| 464 | void PathTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_format) { | 464 | void PatchTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_format) { |
| 465 | const auto it{IR::Block::InstructionList::s_iterator_to(inst)}; | 465 | const auto it{IR::Block::InstructionList::s_iterator_to(inst)}; |
| 466 | IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; | 466 | IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; |
| 467 | auto get_max_value = [pixel_format]() -> float { | 467 | auto get_max_value = [pixel_format]() -> float { |
| @@ -494,7 +494,7 @@ void PathTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_f | |||
| 494 | } | 494 | } |
| 495 | } // Anonymous namespace | 495 | } // Anonymous namespace |
| 496 | 496 | ||
| 497 | void TexturePass(Environment& env, IR::Program& program) { | 497 | void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info) { |
| 498 | TextureInstVector to_replace; | 498 | TextureInstVector to_replace; |
| 499 | for (IR::Block* const block : program.post_order_blocks) { | 499 | for (IR::Block* const block : program.post_order_blocks) { |
| 500 | for (IR::Inst& inst : block->Instructions()) { | 500 | for (IR::Inst& inst : block->Instructions()) { |
| @@ -639,11 +639,11 @@ void TexturePass(Environment& env, IR::Program& program) { | |||
| 639 | inst->SetArg(0, IR::Value{}); | 639 | inst->SetArg(0, IR::Value{}); |
| 640 | } | 640 | } |
| 641 | 641 | ||
| 642 | if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL && | 642 | if (!host_info.support_snorm_render_buffer && inst->GetOpcode() == IR::Opcode::ImageFetch && |
| 643 | inst->GetOpcode() == IR::Opcode::ImageFetch && flags.type == TextureType::Buffer) { | 643 | flags.type == TextureType::Buffer) { |
| 644 | const auto pixel_format = ReadTexturePixelFormat(env, cbuf); | 644 | const auto pixel_format = ReadTexturePixelFormat(env, cbuf); |
| 645 | if (pixel_format != TexturePixelFormat::OTHER) { | 645 | if (pixel_format != TexturePixelFormat::OTHER) { |
| 646 | PathTexelFetch(*texture_inst.block, *texture_inst.inst, pixel_format); | 646 | PatchTexelFetch(*texture_inst.block, *texture_inst.inst, pixel_format); |
| 647 | } | 647 | } |
| 648 | } | 648 | } |
| 649 | } | 649 | } |
diff --git a/src/shader_recompiler/shader_info.h b/src/shader_recompiler/shader_info.h index f31e1f821..ee6252bb5 100644 --- a/src/shader_recompiler/shader_info.h +++ b/src/shader_recompiler/shader_info.h | |||
| @@ -127,6 +127,7 @@ struct Info { | |||
| 127 | bool uses_workgroup_id{}; | 127 | bool uses_workgroup_id{}; |
| 128 | bool uses_local_invocation_id{}; | 128 | bool uses_local_invocation_id{}; |
| 129 | bool uses_invocation_id{}; | 129 | bool uses_invocation_id{}; |
| 130 | bool uses_invocation_info{}; | ||
| 130 | bool uses_sample_id{}; | 131 | bool uses_sample_id{}; |
| 131 | bool uses_is_helper_invocation{}; | 132 | bool uses_is_helper_invocation{}; |
| 132 | bool uses_subgroup_invocation_id{}; | 133 | bool uses_subgroup_invocation_id{}; |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 106991969..d7f7d336c 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -73,8 +73,6 @@ add_library(video_core STATIC | |||
| 73 | macro/macro_hle.h | 73 | macro/macro_hle.h |
| 74 | macro/macro_interpreter.cpp | 74 | macro/macro_interpreter.cpp |
| 75 | macro/macro_interpreter.h | 75 | macro/macro_interpreter.h |
| 76 | macro/macro_jit_x64.cpp | ||
| 77 | macro/macro_jit_x64.h | ||
| 78 | fence_manager.h | 76 | fence_manager.h |
| 79 | gpu.cpp | 77 | gpu.cpp |
| 80 | gpu.h | 78 | gpu.h |
| @@ -245,7 +243,7 @@ add_library(video_core STATIC | |||
| 245 | create_target_directory_groups(video_core) | 243 | create_target_directory_groups(video_core) |
| 246 | 244 | ||
| 247 | target_link_libraries(video_core PUBLIC common core) | 245 | target_link_libraries(video_core PUBLIC common core) |
| 248 | target_link_libraries(video_core PUBLIC glad shader_recompiler xbyak) | 246 | target_link_libraries(video_core PUBLIC glad shader_recompiler) |
| 249 | 247 | ||
| 250 | if (YUZU_USE_BUNDLED_FFMPEG AND NOT WIN32) | 248 | if (YUZU_USE_BUNDLED_FFMPEG AND NOT WIN32) |
| 251 | add_dependencies(video_core ffmpeg-build) | 249 | add_dependencies(video_core ffmpeg-build) |
| @@ -282,8 +280,19 @@ else() | |||
| 282 | 280 | ||
| 283 | -Wno-sign-conversion | 281 | -Wno-sign-conversion |
| 284 | ) | 282 | ) |
| 283 | |||
| 284 | # xbyak | ||
| 285 | set_source_files_properties(macro/macro_jit_x64.cpp PROPERTIES COMPILE_OPTIONS "-Wno-conversion;-Wno-shadow") | ||
| 285 | endif() | 286 | endif() |
| 286 | 287 | ||
| 287 | if (ARCHITECTURE_x86_64) | 288 | if (ARCHITECTURE_x86_64) |
| 289 | target_sources(video_core PRIVATE | ||
| 290 | macro/macro_jit_x64.cpp | ||
| 291 | macro/macro_jit_x64.h | ||
| 292 | ) | ||
| 293 | target_link_libraries(video_core PUBLIC xbyak) | ||
| 294 | endif() | ||
| 295 | |||
| 296 | if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) | ||
| 288 | target_link_libraries(video_core PRIVATE dynarmic) | 297 | target_link_libraries(video_core PRIVATE dynarmic) |
| 289 | endif() | 298 | endif() |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index a948fcb14..910ab213a 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -2970,7 +2970,7 @@ public: | |||
| 2970 | CullFace gl_cull_face; ///< 0x1920 | 2970 | CullFace gl_cull_face; ///< 0x1920 |
| 2971 | Viewport::PixelCenter viewport_pixel_center; ///< 0x1924 | 2971 | Viewport::PixelCenter viewport_pixel_center; ///< 0x1924 |
| 2972 | INSERT_PADDING_BYTES_NOINIT(0x4); | 2972 | INSERT_PADDING_BYTES_NOINIT(0x4); |
| 2973 | u32 viewport_scale_offset_enbled; ///< 0x192C | 2973 | u32 viewport_scale_offset_enabled; ///< 0x192C |
| 2974 | INSERT_PADDING_BYTES_NOINIT(0xC); | 2974 | INSERT_PADDING_BYTES_NOINIT(0xC); |
| 2975 | ViewportClipControl viewport_clip_control; ///< 0x193C | 2975 | ViewportClipControl viewport_clip_control; ///< 0x193C |
| 2976 | UserClip::Op user_clip_op; ///< 0x1940 | 2976 | UserClip::Op user_clip_op; ///< 0x1940 |
| @@ -3482,7 +3482,7 @@ ASSERT_REG_POSITION(gl_cull_test_enabled, 0x1918); | |||
| 3482 | ASSERT_REG_POSITION(gl_front_face, 0x191C); | 3482 | ASSERT_REG_POSITION(gl_front_face, 0x191C); |
| 3483 | ASSERT_REG_POSITION(gl_cull_face, 0x1920); | 3483 | ASSERT_REG_POSITION(gl_cull_face, 0x1920); |
| 3484 | ASSERT_REG_POSITION(viewport_pixel_center, 0x1924); | 3484 | ASSERT_REG_POSITION(viewport_pixel_center, 0x1924); |
| 3485 | ASSERT_REG_POSITION(viewport_scale_offset_enbled, 0x192C); | 3485 | ASSERT_REG_POSITION(viewport_scale_offset_enabled, 0x192C); |
| 3486 | ASSERT_REG_POSITION(viewport_clip_control, 0x193C); | 3486 | ASSERT_REG_POSITION(viewport_clip_control, 0x193C); |
| 3487 | ASSERT_REG_POSITION(user_clip_op, 0x1940); | 3487 | ASSERT_REG_POSITION(user_clip_op, 0x1940); |
| 3488 | ASSERT_REG_POSITION(render_enable_override, 0x1944); | 3488 | ASSERT_REG_POSITION(render_enable_override, 0x1944); |
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index 4eb7a100d..54523a4b2 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp | |||
| @@ -102,26 +102,29 @@ void MaxwellDMA::Launch() { | |||
| 102 | const bool is_src_pitch = IsPitchKind(static_cast<PTEKind>(src_kind)); | 102 | const bool is_src_pitch = IsPitchKind(static_cast<PTEKind>(src_kind)); |
| 103 | const bool is_dst_pitch = IsPitchKind(static_cast<PTEKind>(dst_kind)); | 103 | const bool is_dst_pitch = IsPitchKind(static_cast<PTEKind>(dst_kind)); |
| 104 | if (!is_src_pitch && is_dst_pitch) { | 104 | if (!is_src_pitch && is_dst_pitch) { |
| 105 | std::vector<u8> tmp_buffer(regs.line_length_in); | 105 | UNIMPLEMENTED_IF(regs.line_length_in % 16 != 0); |
| 106 | std::vector<u8> dst_buffer(regs.line_length_in); | 106 | UNIMPLEMENTED_IF(regs.offset_in % 16 != 0); |
| 107 | memory_manager.ReadBlockUnsafe(regs.offset_in, tmp_buffer.data(), | 107 | UNIMPLEMENTED_IF(regs.offset_out % 16 != 0); |
| 108 | regs.line_length_in); | 108 | std::vector<u8> tmp_buffer(16); |
| 109 | for (u32 offset = 0; offset < regs.line_length_in; ++offset) { | 109 | for (u32 offset = 0; offset < regs.line_length_in; offset += 16) { |
| 110 | dst_buffer[offset] = | 110 | memory_manager.ReadBlockUnsafe( |
| 111 | tmp_buffer[convert_linear_2_blocklinear_addr(regs.offset_in + offset) - | 111 | convert_linear_2_blocklinear_addr(regs.offset_in + offset), |
| 112 | regs.offset_in]; | 112 | tmp_buffer.data(), tmp_buffer.size()); |
| 113 | memory_manager.WriteBlock(regs.offset_out + offset, tmp_buffer.data(), | ||
| 114 | tmp_buffer.size()); | ||
| 113 | } | 115 | } |
| 114 | memory_manager.WriteBlock(regs.offset_out, dst_buffer.data(), regs.line_length_in); | ||
| 115 | } else if (is_src_pitch && !is_dst_pitch) { | 116 | } else if (is_src_pitch && !is_dst_pitch) { |
| 116 | std::vector<u8> tmp_buffer(regs.line_length_in); | 117 | UNIMPLEMENTED_IF(regs.line_length_in % 16 != 0); |
| 117 | std::vector<u8> dst_buffer(regs.line_length_in); | 118 | UNIMPLEMENTED_IF(regs.offset_in % 16 != 0); |
| 118 | memory_manager.ReadBlockUnsafe(regs.offset_in, tmp_buffer.data(), | 119 | UNIMPLEMENTED_IF(regs.offset_out % 16 != 0); |
| 119 | regs.line_length_in); | 120 | std::vector<u8> tmp_buffer(16); |
| 120 | for (u32 offset = 0; offset < regs.line_length_in; ++offset) { | 121 | for (u32 offset = 0; offset < regs.line_length_in; offset += 16) { |
| 121 | dst_buffer[convert_linear_2_blocklinear_addr(regs.offset_out + offset) - | 122 | memory_manager.ReadBlockUnsafe(regs.offset_in + offset, tmp_buffer.data(), |
| 122 | regs.offset_out] = tmp_buffer[offset]; | 123 | tmp_buffer.size()); |
| 124 | memory_manager.WriteBlock( | ||
| 125 | convert_linear_2_blocklinear_addr(regs.offset_out + offset), | ||
| 126 | tmp_buffer.data(), tmp_buffer.size()); | ||
| 123 | } | 127 | } |
| 124 | memory_manager.WriteBlock(regs.offset_out, dst_buffer.data(), regs.line_length_in); | ||
| 125 | } else { | 128 | } else { |
| 126 | if (!accelerate.BufferCopy(regs.offset_in, regs.offset_out, regs.line_length_in)) { | 129 | if (!accelerate.BufferCopy(regs.offset_in, regs.offset_out, regs.line_length_in)) { |
| 127 | std::vector<u8> tmp_buffer(regs.line_length_in); | 130 | std::vector<u8> tmp_buffer(regs.line_length_in); |
diff --git a/src/video_core/macro/macro.cpp b/src/video_core/macro/macro.cpp index f61d5998e..505d81c1e 100644 --- a/src/video_core/macro/macro.cpp +++ b/src/video_core/macro/macro.cpp | |||
| @@ -16,7 +16,10 @@ | |||
| 16 | #include "video_core/macro/macro.h" | 16 | #include "video_core/macro/macro.h" |
| 17 | #include "video_core/macro/macro_hle.h" | 17 | #include "video_core/macro/macro_hle.h" |
| 18 | #include "video_core/macro/macro_interpreter.h" | 18 | #include "video_core/macro/macro_interpreter.h" |
| 19 | |||
| 20 | #ifdef ARCHITECTURE_x86_64 | ||
| 19 | #include "video_core/macro/macro_jit_x64.h" | 21 | #include "video_core/macro/macro_jit_x64.h" |
| 22 | #endif | ||
| 20 | 23 | ||
| 21 | namespace Tegra { | 24 | namespace Tegra { |
| 22 | 25 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 72e314d39..8a8b5ce54 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -618,7 +618,7 @@ void RasterizerOpenGL::SyncViewport() { | |||
| 618 | } | 618 | } |
| 619 | flags[Dirty::Viewport0 + index] = false; | 619 | flags[Dirty::Viewport0 + index] = false; |
| 620 | 620 | ||
| 621 | if (!regs.viewport_scale_offset_enbled) { | 621 | if (!regs.viewport_scale_offset_enabled) { |
| 622 | const auto x = static_cast<GLfloat>(regs.surface_clip.x); | 622 | const auto x = static_cast<GLfloat>(regs.surface_clip.x); |
| 623 | const auto y = static_cast<GLfloat>(regs.surface_clip.y); | 623 | const auto y = static_cast<GLfloat>(regs.surface_clip.y); |
| 624 | const auto width = static_cast<GLfloat>(regs.surface_clip.width); | 624 | const auto width = static_cast<GLfloat>(regs.surface_clip.width); |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 977709518..3fe04a115 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -76,7 +76,8 @@ Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key, | |||
| 76 | } | 76 | } |
| 77 | break; | 77 | break; |
| 78 | case Shader::Stage::TessellationEval: | 78 | case Shader::Stage::TessellationEval: |
| 79 | info.tess_clockwise = key.tessellation_clockwise != 0; | 79 | // Flip the face, as OpenGL's drawing is flipped. |
| 80 | info.tess_clockwise = key.tessellation_clockwise == 0; | ||
| 80 | info.tess_primitive = [&key] { | 81 | info.tess_primitive = [&key] { |
| 81 | switch (key.tessellation_primitive) { | 82 | switch (key.tessellation_primitive) { |
| 82 | case Maxwell::Tessellation::DomainType::Isolines: | 83 | case Maxwell::Tessellation::DomainType::Isolines: |
| @@ -218,6 +219,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo | |||
| 218 | .support_float16 = false, | 219 | .support_float16 = false, |
| 219 | .support_int64 = device.HasShaderInt64(), | 220 | .support_int64 = device.HasShaderInt64(), |
| 220 | .needs_demote_reorder = device.IsAmd(), | 221 | .needs_demote_reorder = device.IsAmd(), |
| 222 | .support_snorm_render_buffer = false, | ||
| 221 | } { | 223 | } { |
| 222 | if (use_asynchronous_shaders) { | 224 | if (use_asynchronous_shaders) { |
| 223 | workers = CreateWorkers(); | 225 | workers = CreateWorkers(); |
diff --git a/src/video_core/renderer_opengl/gl_state_tracker.cpp b/src/video_core/renderer_opengl/gl_state_tracker.cpp index a359f96f1..d53b422ca 100644 --- a/src/video_core/renderer_opengl/gl_state_tracker.cpp +++ b/src/video_core/renderer_opengl/gl_state_tracker.cpp | |||
| @@ -70,8 +70,8 @@ void SetupDirtyViewports(Tables& tables) { | |||
| 70 | FillBlock(tables[1], OFF(viewport_transform), NUM(viewport_transform), Viewports); | 70 | FillBlock(tables[1], OFF(viewport_transform), NUM(viewport_transform), Viewports); |
| 71 | FillBlock(tables[1], OFF(viewports), NUM(viewports), Viewports); | 71 | FillBlock(tables[1], OFF(viewports), NUM(viewports), Viewports); |
| 72 | 72 | ||
| 73 | tables[0][OFF(viewport_scale_offset_enbled)] = ViewportTransform; | 73 | tables[0][OFF(viewport_scale_offset_enabled)] = ViewportTransform; |
| 74 | tables[1][OFF(viewport_scale_offset_enbled)] = Viewports; | 74 | tables[1][OFF(viewport_scale_offset_enabled)] = Viewports; |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | void SetupDirtyScissors(Tables& tables) { | 77 | void SetupDirtyScissors(Tables& tables) { |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index b42e5be1e..d4b0a542a 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -166,6 +166,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program | |||
| 166 | } | 166 | } |
| 167 | break; | 167 | break; |
| 168 | case Shader::Stage::TessellationEval: | 168 | case Shader::Stage::TessellationEval: |
| 169 | info.tess_clockwise = key.state.tessellation_clockwise != 0; | ||
| 169 | info.tess_primitive = [&key] { | 170 | info.tess_primitive = [&key] { |
| 170 | const u32 raw{key.state.tessellation_primitive.Value()}; | 171 | const u32 raw{key.state.tessellation_primitive.Value()}; |
| 171 | switch (static_cast<Maxwell::Tessellation::DomainType>(raw)) { | 172 | switch (static_cast<Maxwell::Tessellation::DomainType>(raw)) { |
| @@ -325,6 +326,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device | |||
| 325 | .support_int64 = device.IsShaderInt64Supported(), | 326 | .support_int64 = device.IsShaderInt64Supported(), |
| 326 | .needs_demote_reorder = driver_id == VK_DRIVER_ID_AMD_PROPRIETARY_KHR || | 327 | .needs_demote_reorder = driver_id == VK_DRIVER_ID_AMD_PROPRIETARY_KHR || |
| 327 | driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR, | 328 | driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR, |
| 329 | .support_snorm_render_buffer = true, | ||
| 328 | }; | 330 | }; |
| 329 | } | 331 | } |
| 330 | 332 | ||
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index f79fa8313..f69c0c50f 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -683,7 +683,7 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg | |||
| 683 | if (!state_tracker.TouchViewports()) { | 683 | if (!state_tracker.TouchViewports()) { |
| 684 | return; | 684 | return; |
| 685 | } | 685 | } |
| 686 | if (!regs.viewport_scale_offset_enbled) { | 686 | if (!regs.viewport_scale_offset_enabled) { |
| 687 | const auto x = static_cast<float>(regs.surface_clip.x); | 687 | const auto x = static_cast<float>(regs.surface_clip.x); |
| 688 | const auto y = static_cast<float>(regs.surface_clip.y); | 688 | const auto y = static_cast<float>(regs.surface_clip.y); |
| 689 | const auto width = static_cast<float>(regs.surface_clip.width); | 689 | const auto width = static_cast<float>(regs.surface_clip.width); |
diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp index b87c3be66..edb41b171 100644 --- a/src/video_core/renderer_vulkan/vk_state_tracker.cpp +++ b/src/video_core/renderer_vulkan/vk_state_tracker.cpp | |||
| @@ -51,7 +51,7 @@ Flags MakeInvalidationFlags() { | |||
| 51 | void SetupDirtyViewports(Tables& tables) { | 51 | void SetupDirtyViewports(Tables& tables) { |
| 52 | FillBlock(tables[0], OFF(viewport_transform), NUM(viewport_transform), Viewports); | 52 | FillBlock(tables[0], OFF(viewport_transform), NUM(viewport_transform), Viewports); |
| 53 | FillBlock(tables[0], OFF(viewports), NUM(viewports), Viewports); | 53 | FillBlock(tables[0], OFF(viewports), NUM(viewports), Viewports); |
| 54 | tables[0][OFF(viewport_scale_offset_enbled)] = Viewports; | 54 | tables[0][OFF(viewport_scale_offset_enabled)] = Viewports; |
| 55 | tables[1][OFF(window_origin)] = Viewports; | 55 | tables[1][OFF(window_origin)] = Viewports; |
| 56 | } | 56 | } |
| 57 | 57 | ||
diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp index 37bb76b72..f24f320b6 100644 --- a/src/video_core/shader_environment.cpp +++ b/src/video_core/shader_environment.cpp | |||
| @@ -352,7 +352,7 @@ Shader::TexturePixelFormat GraphicsEnvironment::ReadTexturePixelFormat(u32 handl | |||
| 352 | 352 | ||
| 353 | u32 GraphicsEnvironment::ReadViewportTransformState() { | 353 | u32 GraphicsEnvironment::ReadViewportTransformState() { |
| 354 | const auto& regs{maxwell3d->regs}; | 354 | const auto& regs{maxwell3d->regs}; |
| 355 | viewport_transform_state = regs.viewport_scale_offset_enbled; | 355 | viewport_transform_state = regs.viewport_scale_offset_enabled; |
| 356 | return viewport_transform_state; | 356 | return viewport_transform_state; |
| 357 | } | 357 | } |
| 358 | 358 | ||
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 239f12382..5cc1fbf32 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -385,6 +385,6 @@ if (NOT APPLE) | |||
| 385 | target_compile_definitions(yuzu PRIVATE HAS_OPENGL) | 385 | target_compile_definitions(yuzu PRIVATE HAS_OPENGL) |
| 386 | endif() | 386 | endif() |
| 387 | 387 | ||
| 388 | if (ARCHITECTURE_x86_64) | 388 | if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) |
| 389 | target_link_libraries(yuzu PRIVATE dynarmic) | 389 | target_link_libraries(yuzu PRIVATE dynarmic) |
| 390 | endif() | 390 | endif() |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 6acfb7b06..d88efacd7 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -401,224 +401,127 @@ void GRenderWindow::closeEvent(QCloseEvent* event) { | |||
| 401 | } | 401 | } |
| 402 | 402 | ||
| 403 | int GRenderWindow::QtKeyToSwitchKey(Qt::Key qt_key) { | 403 | int GRenderWindow::QtKeyToSwitchKey(Qt::Key qt_key) { |
| 404 | switch (qt_key) { | 404 | static constexpr std::array<std::pair<Qt::Key, Settings::NativeKeyboard::Keys>, 106> key_map = { |
| 405 | case Qt::Key_A: | 405 | std::pair<Qt::Key, Settings::NativeKeyboard::Keys>{Qt::Key_A, Settings::NativeKeyboard::A}, |
| 406 | return Settings::NativeKeyboard::A; | 406 | {Qt::Key_A, Settings::NativeKeyboard::A}, |
| 407 | case Qt::Key_B: | 407 | {Qt::Key_B, Settings::NativeKeyboard::B}, |
| 408 | return Settings::NativeKeyboard::B; | 408 | {Qt::Key_C, Settings::NativeKeyboard::C}, |
| 409 | case Qt::Key_C: | 409 | {Qt::Key_D, Settings::NativeKeyboard::D}, |
| 410 | return Settings::NativeKeyboard::C; | 410 | {Qt::Key_E, Settings::NativeKeyboard::E}, |
| 411 | case Qt::Key_D: | 411 | {Qt::Key_F, Settings::NativeKeyboard::F}, |
| 412 | return Settings::NativeKeyboard::D; | 412 | {Qt::Key_G, Settings::NativeKeyboard::G}, |
| 413 | case Qt::Key_E: | 413 | {Qt::Key_H, Settings::NativeKeyboard::H}, |
| 414 | return Settings::NativeKeyboard::E; | 414 | {Qt::Key_I, Settings::NativeKeyboard::I}, |
| 415 | case Qt::Key_F: | 415 | {Qt::Key_J, Settings::NativeKeyboard::J}, |
| 416 | return Settings::NativeKeyboard::F; | 416 | {Qt::Key_K, Settings::NativeKeyboard::K}, |
| 417 | case Qt::Key_G: | 417 | {Qt::Key_L, Settings::NativeKeyboard::L}, |
| 418 | return Settings::NativeKeyboard::G; | 418 | {Qt::Key_M, Settings::NativeKeyboard::M}, |
| 419 | case Qt::Key_H: | 419 | {Qt::Key_N, Settings::NativeKeyboard::N}, |
| 420 | return Settings::NativeKeyboard::H; | 420 | {Qt::Key_O, Settings::NativeKeyboard::O}, |
| 421 | case Qt::Key_I: | 421 | {Qt::Key_P, Settings::NativeKeyboard::P}, |
| 422 | return Settings::NativeKeyboard::I; | 422 | {Qt::Key_Q, Settings::NativeKeyboard::Q}, |
| 423 | case Qt::Key_J: | 423 | {Qt::Key_R, Settings::NativeKeyboard::R}, |
| 424 | return Settings::NativeKeyboard::J; | 424 | {Qt::Key_S, Settings::NativeKeyboard::S}, |
| 425 | case Qt::Key_K: | 425 | {Qt::Key_T, Settings::NativeKeyboard::T}, |
| 426 | return Settings::NativeKeyboard::K; | 426 | {Qt::Key_U, Settings::NativeKeyboard::U}, |
| 427 | case Qt::Key_L: | 427 | {Qt::Key_V, Settings::NativeKeyboard::V}, |
| 428 | return Settings::NativeKeyboard::L; | 428 | {Qt::Key_W, Settings::NativeKeyboard::W}, |
| 429 | case Qt::Key_M: | 429 | {Qt::Key_X, Settings::NativeKeyboard::X}, |
| 430 | return Settings::NativeKeyboard::M; | 430 | {Qt::Key_Y, Settings::NativeKeyboard::Y}, |
| 431 | case Qt::Key_N: | 431 | {Qt::Key_Z, Settings::NativeKeyboard::Z}, |
| 432 | return Settings::NativeKeyboard::N; | 432 | {Qt::Key_1, Settings::NativeKeyboard::N1}, |
| 433 | case Qt::Key_O: | 433 | {Qt::Key_2, Settings::NativeKeyboard::N2}, |
| 434 | return Settings::NativeKeyboard::O; | 434 | {Qt::Key_3, Settings::NativeKeyboard::N3}, |
| 435 | case Qt::Key_P: | 435 | {Qt::Key_4, Settings::NativeKeyboard::N4}, |
| 436 | return Settings::NativeKeyboard::P; | 436 | {Qt::Key_5, Settings::NativeKeyboard::N5}, |
| 437 | case Qt::Key_Q: | 437 | {Qt::Key_6, Settings::NativeKeyboard::N6}, |
| 438 | return Settings::NativeKeyboard::Q; | 438 | {Qt::Key_7, Settings::NativeKeyboard::N7}, |
| 439 | case Qt::Key_R: | 439 | {Qt::Key_8, Settings::NativeKeyboard::N8}, |
| 440 | return Settings::NativeKeyboard::R; | 440 | {Qt::Key_9, Settings::NativeKeyboard::N9}, |
| 441 | case Qt::Key_S: | 441 | {Qt::Key_0, Settings::NativeKeyboard::N0}, |
| 442 | return Settings::NativeKeyboard::S; | 442 | {Qt::Key_Return, Settings::NativeKeyboard::Return}, |
| 443 | case Qt::Key_T: | 443 | {Qt::Key_Escape, Settings::NativeKeyboard::Escape}, |
| 444 | return Settings::NativeKeyboard::T; | 444 | {Qt::Key_Backspace, Settings::NativeKeyboard::Backspace}, |
| 445 | case Qt::Key_U: | 445 | {Qt::Key_Tab, Settings::NativeKeyboard::Tab}, |
| 446 | return Settings::NativeKeyboard::U; | 446 | {Qt::Key_Space, Settings::NativeKeyboard::Space}, |
| 447 | case Qt::Key_V: | 447 | {Qt::Key_Minus, Settings::NativeKeyboard::Minus}, |
| 448 | return Settings::NativeKeyboard::V; | 448 | {Qt::Key_Plus, Settings::NativeKeyboard::Plus}, |
| 449 | case Qt::Key_W: | 449 | {Qt::Key_questiondown, Settings::NativeKeyboard::Plus}, |
| 450 | return Settings::NativeKeyboard::W; | 450 | {Qt::Key_BracketLeft, Settings::NativeKeyboard::OpenBracket}, |
| 451 | case Qt::Key_X: | 451 | {Qt::Key_BraceLeft, Settings::NativeKeyboard::OpenBracket}, |
| 452 | return Settings::NativeKeyboard::X; | 452 | {Qt::Key_BracketRight, Settings::NativeKeyboard::CloseBracket}, |
| 453 | case Qt::Key_Y: | 453 | {Qt::Key_BraceRight, Settings::NativeKeyboard::CloseBracket}, |
| 454 | return Settings::NativeKeyboard::Y; | 454 | {Qt::Key_Bar, Settings::NativeKeyboard::Pipe}, |
| 455 | case Qt::Key_Z: | 455 | {Qt::Key_Dead_Tilde, Settings::NativeKeyboard::Tilde}, |
| 456 | return Settings::NativeKeyboard::Z; | 456 | {Qt::Key_Ntilde, Settings::NativeKeyboard::Semicolon}, |
| 457 | case Qt::Key_1: | 457 | {Qt::Key_Semicolon, Settings::NativeKeyboard::Semicolon}, |
| 458 | return Settings::NativeKeyboard::N1; | 458 | {Qt::Key_Apostrophe, Settings::NativeKeyboard::Quote}, |
| 459 | case Qt::Key_2: | 459 | {Qt::Key_Dead_Grave, Settings::NativeKeyboard::Backquote}, |
| 460 | return Settings::NativeKeyboard::N2; | 460 | {Qt::Key_Comma, Settings::NativeKeyboard::Comma}, |
| 461 | case Qt::Key_3: | 461 | {Qt::Key_Period, Settings::NativeKeyboard::Period}, |
| 462 | return Settings::NativeKeyboard::N3; | 462 | {Qt::Key_Slash, Settings::NativeKeyboard::Slash}, |
| 463 | case Qt::Key_4: | 463 | {Qt::Key_CapsLock, Settings::NativeKeyboard::CapsLockKey}, |
| 464 | return Settings::NativeKeyboard::N4; | 464 | {Qt::Key_F1, Settings::NativeKeyboard::F1}, |
| 465 | case Qt::Key_5: | 465 | {Qt::Key_F2, Settings::NativeKeyboard::F2}, |
| 466 | return Settings::NativeKeyboard::N5; | 466 | {Qt::Key_F3, Settings::NativeKeyboard::F3}, |
| 467 | case Qt::Key_6: | 467 | {Qt::Key_F4, Settings::NativeKeyboard::F4}, |
| 468 | return Settings::NativeKeyboard::N6; | 468 | {Qt::Key_F5, Settings::NativeKeyboard::F5}, |
| 469 | case Qt::Key_7: | 469 | {Qt::Key_F6, Settings::NativeKeyboard::F6}, |
| 470 | return Settings::NativeKeyboard::N7; | 470 | {Qt::Key_F7, Settings::NativeKeyboard::F7}, |
| 471 | case Qt::Key_8: | 471 | {Qt::Key_F8, Settings::NativeKeyboard::F8}, |
| 472 | return Settings::NativeKeyboard::N8; | 472 | {Qt::Key_F9, Settings::NativeKeyboard::F9}, |
| 473 | case Qt::Key_9: | 473 | {Qt::Key_F10, Settings::NativeKeyboard::F10}, |
| 474 | return Settings::NativeKeyboard::N9; | 474 | {Qt::Key_F11, Settings::NativeKeyboard::F11}, |
| 475 | case Qt::Key_0: | 475 | {Qt::Key_F12, Settings::NativeKeyboard::F12}, |
| 476 | return Settings::NativeKeyboard::N0; | 476 | {Qt::Key_Print, Settings::NativeKeyboard::PrintScreen}, |
| 477 | case Qt::Key_Return: | 477 | {Qt::Key_ScrollLock, Settings::NativeKeyboard::ScrollLockKey}, |
| 478 | return Settings::NativeKeyboard::Return; | 478 | {Qt::Key_Pause, Settings::NativeKeyboard::Pause}, |
| 479 | case Qt::Key_Escape: | 479 | {Qt::Key_Insert, Settings::NativeKeyboard::Insert}, |
| 480 | return Settings::NativeKeyboard::Escape; | 480 | {Qt::Key_Home, Settings::NativeKeyboard::Home}, |
| 481 | case Qt::Key_Backspace: | 481 | {Qt::Key_PageUp, Settings::NativeKeyboard::PageUp}, |
| 482 | return Settings::NativeKeyboard::Backspace; | 482 | {Qt::Key_Delete, Settings::NativeKeyboard::Delete}, |
| 483 | case Qt::Key_Tab: | 483 | {Qt::Key_End, Settings::NativeKeyboard::End}, |
| 484 | return Settings::NativeKeyboard::Tab; | 484 | {Qt::Key_PageDown, Settings::NativeKeyboard::PageDown}, |
| 485 | case Qt::Key_Space: | 485 | {Qt::Key_Right, Settings::NativeKeyboard::Right}, |
| 486 | return Settings::NativeKeyboard::Space; | 486 | {Qt::Key_Left, Settings::NativeKeyboard::Left}, |
| 487 | case Qt::Key_Minus: | 487 | {Qt::Key_Down, Settings::NativeKeyboard::Down}, |
| 488 | return Settings::NativeKeyboard::Minus; | 488 | {Qt::Key_Up, Settings::NativeKeyboard::Up}, |
| 489 | case Qt::Key_Plus: | 489 | {Qt::Key_NumLock, Settings::NativeKeyboard::NumLockKey}, |
| 490 | case Qt::Key_questiondown: | 490 | // Numpad keys are missing here |
| 491 | return Settings::NativeKeyboard::Plus; | 491 | {Qt::Key_F13, Settings::NativeKeyboard::F13}, |
| 492 | case Qt::Key_BracketLeft: | 492 | {Qt::Key_F14, Settings::NativeKeyboard::F14}, |
| 493 | case Qt::Key_BraceLeft: | 493 | {Qt::Key_F15, Settings::NativeKeyboard::F15}, |
| 494 | return Settings::NativeKeyboard::OpenBracket; | 494 | {Qt::Key_F16, Settings::NativeKeyboard::F16}, |
| 495 | case Qt::Key_BracketRight: | 495 | {Qt::Key_F17, Settings::NativeKeyboard::F17}, |
| 496 | case Qt::Key_BraceRight: | 496 | {Qt::Key_F18, Settings::NativeKeyboard::F18}, |
| 497 | return Settings::NativeKeyboard::CloseBracket; | 497 | {Qt::Key_F19, Settings::NativeKeyboard::F19}, |
| 498 | case Qt::Key_Bar: | 498 | {Qt::Key_F20, Settings::NativeKeyboard::F20}, |
| 499 | return Settings::NativeKeyboard::Pipe; | 499 | {Qt::Key_F21, Settings::NativeKeyboard::F21}, |
| 500 | case Qt::Key_Dead_Tilde: | 500 | {Qt::Key_F22, Settings::NativeKeyboard::F22}, |
| 501 | return Settings::NativeKeyboard::Tilde; | 501 | {Qt::Key_F23, Settings::NativeKeyboard::F23}, |
| 502 | case Qt::Key_Ntilde: | 502 | {Qt::Key_F24, Settings::NativeKeyboard::F24}, |
| 503 | case Qt::Key_Semicolon: | 503 | // {Qt::..., Settings::NativeKeyboard::KPComma}, |
| 504 | return Settings::NativeKeyboard::Semicolon; | 504 | // {Qt::..., Settings::NativeKeyboard::Ro}, |
| 505 | case Qt::Key_Apostrophe: | 505 | {Qt::Key_Hiragana_Katakana, Settings::NativeKeyboard::KatakanaHiragana}, |
| 506 | return Settings::NativeKeyboard::Quote; | 506 | {Qt::Key_yen, Settings::NativeKeyboard::Yen}, |
| 507 | case Qt::Key_Dead_Grave: | 507 | {Qt::Key_Henkan, Settings::NativeKeyboard::Henkan}, |
| 508 | return Settings::NativeKeyboard::Backquote; | 508 | {Qt::Key_Muhenkan, Settings::NativeKeyboard::Muhenkan}, |
| 509 | case Qt::Key_Comma: | 509 | // {Qt::..., Settings::NativeKeyboard::NumPadCommaPc98}, |
| 510 | return Settings::NativeKeyboard::Comma; | 510 | {Qt::Key_Hangul, Settings::NativeKeyboard::HangulEnglish}, |
| 511 | case Qt::Key_Period: | 511 | {Qt::Key_Hangul_Hanja, Settings::NativeKeyboard::Hanja}, |
| 512 | return Settings::NativeKeyboard::Period; | 512 | {Qt::Key_Katakana, Settings::NativeKeyboard::KatakanaKey}, |
| 513 | case Qt::Key_Slash: | 513 | {Qt::Key_Hiragana, Settings::NativeKeyboard::HiraganaKey}, |
| 514 | return Settings::NativeKeyboard::Slash; | 514 | {Qt::Key_Zenkaku_Hankaku, Settings::NativeKeyboard::ZenkakuHankaku}, |
| 515 | case Qt::Key_CapsLock: | 515 | // Modifier keys are handled by the modifier property |
| 516 | return Settings::NativeKeyboard::CapsLock; | 516 | }; |
| 517 | case Qt::Key_F1: | 517 | |
| 518 | return Settings::NativeKeyboard::F1; | 518 | for (const auto& [qkey, nkey] : key_map) { |
| 519 | case Qt::Key_F2: | 519 | if (qt_key == qkey) { |
| 520 | return Settings::NativeKeyboard::F2; | 520 | return nkey; |
| 521 | case Qt::Key_F3: | 521 | } |
| 522 | return Settings::NativeKeyboard::F3; | ||
| 523 | case Qt::Key_F4: | ||
| 524 | return Settings::NativeKeyboard::F4; | ||
| 525 | case Qt::Key_F5: | ||
| 526 | return Settings::NativeKeyboard::F5; | ||
| 527 | case Qt::Key_F6: | ||
| 528 | return Settings::NativeKeyboard::F6; | ||
| 529 | case Qt::Key_F7: | ||
| 530 | return Settings::NativeKeyboard::F7; | ||
| 531 | case Qt::Key_F8: | ||
| 532 | return Settings::NativeKeyboard::F8; | ||
| 533 | case Qt::Key_F9: | ||
| 534 | return Settings::NativeKeyboard::F9; | ||
| 535 | case Qt::Key_F10: | ||
| 536 | return Settings::NativeKeyboard::F10; | ||
| 537 | case Qt::Key_F11: | ||
| 538 | return Settings::NativeKeyboard::F11; | ||
| 539 | case Qt::Key_F12: | ||
| 540 | return Settings::NativeKeyboard::F12; | ||
| 541 | case Qt::Key_Print: | ||
| 542 | return Settings::NativeKeyboard::PrintScreen; | ||
| 543 | case Qt::Key_ScrollLock: | ||
| 544 | return Settings::NativeKeyboard::ScrollLock; | ||
| 545 | case Qt::Key_Pause: | ||
| 546 | return Settings::NativeKeyboard::Pause; | ||
| 547 | case Qt::Key_Insert: | ||
| 548 | return Settings::NativeKeyboard::Insert; | ||
| 549 | case Qt::Key_Home: | ||
| 550 | return Settings::NativeKeyboard::Home; | ||
| 551 | case Qt::Key_PageUp: | ||
| 552 | return Settings::NativeKeyboard::PageUp; | ||
| 553 | case Qt::Key_Delete: | ||
| 554 | return Settings::NativeKeyboard::Delete; | ||
| 555 | case Qt::Key_End: | ||
| 556 | return Settings::NativeKeyboard::End; | ||
| 557 | case Qt::Key_PageDown: | ||
| 558 | return Settings::NativeKeyboard::PageDown; | ||
| 559 | case Qt::Key_Right: | ||
| 560 | return Settings::NativeKeyboard::Right; | ||
| 561 | case Qt::Key_Left: | ||
| 562 | return Settings::NativeKeyboard::Left; | ||
| 563 | case Qt::Key_Down: | ||
| 564 | return Settings::NativeKeyboard::Down; | ||
| 565 | case Qt::Key_Up: | ||
| 566 | return Settings::NativeKeyboard::Up; | ||
| 567 | case Qt::Key_NumLock: | ||
| 568 | return Settings::NativeKeyboard::NumLock; | ||
| 569 | // Numpad keys are missing here | ||
| 570 | case Qt::Key_F13: | ||
| 571 | return Settings::NativeKeyboard::F13; | ||
| 572 | case Qt::Key_F14: | ||
| 573 | return Settings::NativeKeyboard::F14; | ||
| 574 | case Qt::Key_F15: | ||
| 575 | return Settings::NativeKeyboard::F15; | ||
| 576 | case Qt::Key_F16: | ||
| 577 | return Settings::NativeKeyboard::F16; | ||
| 578 | case Qt::Key_F17: | ||
| 579 | return Settings::NativeKeyboard::F17; | ||
| 580 | case Qt::Key_F18: | ||
| 581 | return Settings::NativeKeyboard::F18; | ||
| 582 | case Qt::Key_F19: | ||
| 583 | return Settings::NativeKeyboard::F19; | ||
| 584 | case Qt::Key_F20: | ||
| 585 | return Settings::NativeKeyboard::F20; | ||
| 586 | case Qt::Key_F21: | ||
| 587 | return Settings::NativeKeyboard::F21; | ||
| 588 | case Qt::Key_F22: | ||
| 589 | return Settings::NativeKeyboard::F22; | ||
| 590 | case Qt::Key_F23: | ||
| 591 | return Settings::NativeKeyboard::F23; | ||
| 592 | case Qt::Key_F24: | ||
| 593 | return Settings::NativeKeyboard::F24; | ||
| 594 | // case Qt::: | ||
| 595 | // return Settings::NativeKeyboard::KPComma; | ||
| 596 | // case Qt::: | ||
| 597 | // return Settings::NativeKeyboard::Ro; | ||
| 598 | case Qt::Key_Hiragana_Katakana: | ||
| 599 | return Settings::NativeKeyboard::KatakanaHiragana; | ||
| 600 | case Qt::Key_yen: | ||
| 601 | return Settings::NativeKeyboard::Yen; | ||
| 602 | case Qt::Key_Henkan: | ||
| 603 | return Settings::NativeKeyboard::Henkan; | ||
| 604 | case Qt::Key_Muhenkan: | ||
| 605 | return Settings::NativeKeyboard::Muhenkan; | ||
| 606 | // case Qt::: | ||
| 607 | // return Settings::NativeKeyboard::NumPadCommaPc98; | ||
| 608 | case Qt::Key_Hangul: | ||
| 609 | return Settings::NativeKeyboard::HangulEnglish; | ||
| 610 | case Qt::Key_Hangul_Hanja: | ||
| 611 | return Settings::NativeKeyboard::Hanja; | ||
| 612 | case Qt::Key_Katakana: | ||
| 613 | return Settings::NativeKeyboard::KatakanaKey; | ||
| 614 | case Qt::Key_Hiragana: | ||
| 615 | return Settings::NativeKeyboard::HiraganaKey; | ||
| 616 | case Qt::Key_Zenkaku_Hankaku: | ||
| 617 | return Settings::NativeKeyboard::ZenkakuHankaku; | ||
| 618 | // Modifier keys are handled by the modifier property | ||
| 619 | default: | ||
| 620 | return Settings::NativeKeyboard::None; | ||
| 621 | } | 522 | } |
| 523 | |||
| 524 | return Settings::NativeKeyboard::None; | ||
| 622 | } | 525 | } |
| 623 | 526 | ||
| 624 | int GRenderWindow::QtModifierToSwitchModifier(Qt::KeyboardModifiers qt_modifiers) { | 527 | int GRenderWindow::QtModifierToSwitchModifier(Qt::KeyboardModifiers qt_modifiers) { |
diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp index f46fff340..b03e71248 100644 --- a/src/yuzu/compatdb.cpp +++ b/src/yuzu/compatdb.cpp | |||
| @@ -15,12 +15,22 @@ CompatDB::CompatDB(Core::TelemetrySession& telemetry_session_, QWidget* parent) | |||
| 15 | : QWizard(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), | 15 | : QWizard(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), |
| 16 | ui{std::make_unique<Ui::CompatDB>()}, telemetry_session{telemetry_session_} { | 16 | ui{std::make_unique<Ui::CompatDB>()}, telemetry_session{telemetry_session_} { |
| 17 | ui->setupUi(this); | 17 | ui->setupUi(this); |
| 18 | connect(ui->radioButton_Perfect, &QRadioButton::clicked, this, &CompatDB::EnableNext); | 18 | |
| 19 | connect(ui->radioButton_Great, &QRadioButton::clicked, this, &CompatDB::EnableNext); | 19 | connect(ui->radioButton_GameBoot_Yes, &QRadioButton::clicked, this, &CompatDB::EnableNext); |
| 20 | connect(ui->radioButton_Okay, &QRadioButton::clicked, this, &CompatDB::EnableNext); | 20 | connect(ui->radioButton_GameBoot_No, &QRadioButton::clicked, this, &CompatDB::EnableNext); |
| 21 | connect(ui->radioButton_Bad, &QRadioButton::clicked, this, &CompatDB::EnableNext); | 21 | connect(ui->radioButton_Gameplay_Yes, &QRadioButton::clicked, this, &CompatDB::EnableNext); |
| 22 | connect(ui->radioButton_IntroMenu, &QRadioButton::clicked, this, &CompatDB::EnableNext); | 22 | connect(ui->radioButton_Gameplay_No, &QRadioButton::clicked, this, &CompatDB::EnableNext); |
| 23 | connect(ui->radioButton_WontBoot, &QRadioButton::clicked, this, &CompatDB::EnableNext); | 23 | connect(ui->radioButton_NoFreeze_Yes, &QRadioButton::clicked, this, &CompatDB::EnableNext); |
| 24 | connect(ui->radioButton_NoFreeze_No, &QRadioButton::clicked, this, &CompatDB::EnableNext); | ||
| 25 | connect(ui->radioButton_Complete_Yes, &QRadioButton::clicked, this, &CompatDB::EnableNext); | ||
| 26 | connect(ui->radioButton_Complete_No, &QRadioButton::clicked, this, &CompatDB::EnableNext); | ||
| 27 | connect(ui->radioButton_Graphical_Major, &QRadioButton::clicked, this, &CompatDB::EnableNext); | ||
| 28 | connect(ui->radioButton_Graphical_Minor, &QRadioButton::clicked, this, &CompatDB::EnableNext); | ||
| 29 | connect(ui->radioButton_Graphical_No, &QRadioButton::clicked, this, &CompatDB::EnableNext); | ||
| 30 | connect(ui->radioButton_Audio_Major, &QRadioButton::clicked, this, &CompatDB::EnableNext); | ||
| 31 | connect(ui->radioButton_Audio_Minor, &QRadioButton::clicked, this, &CompatDB::EnableNext); | ||
| 32 | connect(ui->radioButton_Audio_No, &QRadioButton::clicked, this, &CompatDB::EnableNext); | ||
| 33 | |||
| 24 | connect(button(NextButton), &QPushButton::clicked, this, &CompatDB::Submit); | 34 | connect(button(NextButton), &QPushButton::clicked, this, &CompatDB::Submit); |
| 25 | connect(&testcase_watcher, &QFutureWatcher<bool>::finished, this, | 35 | connect(&testcase_watcher, &QFutureWatcher<bool>::finished, this, |
| 26 | &CompatDB::OnTestcaseSubmitted); | 36 | &CompatDB::OnTestcaseSubmitted); |
| @@ -30,29 +40,82 @@ CompatDB::~CompatDB() = default; | |||
| 30 | 40 | ||
| 31 | enum class CompatDBPage { | 41 | enum class CompatDBPage { |
| 32 | Intro = 0, | 42 | Intro = 0, |
| 33 | Selection = 1, | 43 | GameBoot = 1, |
| 34 | Final = 2, | 44 | GamePlay = 2, |
| 45 | Freeze = 3, | ||
| 46 | Completion = 4, | ||
| 47 | Graphical = 5, | ||
| 48 | Audio = 6, | ||
| 49 | Final = 7, | ||
| 35 | }; | 50 | }; |
| 36 | 51 | ||
| 37 | void CompatDB::Submit() { | 52 | void CompatDB::Submit() { |
| 38 | QButtonGroup* compatibility = new QButtonGroup(this); | 53 | QButtonGroup* compatibility_GameBoot = new QButtonGroup(this); |
| 39 | compatibility->addButton(ui->radioButton_Perfect, 0); | 54 | compatibility_GameBoot->addButton(ui->radioButton_GameBoot_Yes, 0); |
| 40 | compatibility->addButton(ui->radioButton_Great, 1); | 55 | compatibility_GameBoot->addButton(ui->radioButton_GameBoot_No, 1); |
| 41 | compatibility->addButton(ui->radioButton_Okay, 2); | 56 | |
| 42 | compatibility->addButton(ui->radioButton_Bad, 3); | 57 | QButtonGroup* compatibility_Gameplay = new QButtonGroup(this); |
| 43 | compatibility->addButton(ui->radioButton_IntroMenu, 4); | 58 | compatibility_Gameplay->addButton(ui->radioButton_Gameplay_Yes, 0); |
| 44 | compatibility->addButton(ui->radioButton_WontBoot, 5); | 59 | compatibility_Gameplay->addButton(ui->radioButton_Gameplay_No, 1); |
| 60 | |||
| 61 | QButtonGroup* compatibility_NoFreeze = new QButtonGroup(this); | ||
| 62 | compatibility_NoFreeze->addButton(ui->radioButton_NoFreeze_Yes, 0); | ||
| 63 | compatibility_NoFreeze->addButton(ui->radioButton_NoFreeze_No, 1); | ||
| 64 | |||
| 65 | QButtonGroup* compatibility_Complete = new QButtonGroup(this); | ||
| 66 | compatibility_Complete->addButton(ui->radioButton_Complete_Yes, 0); | ||
| 67 | compatibility_Complete->addButton(ui->radioButton_Complete_No, 1); | ||
| 68 | |||
| 69 | QButtonGroup* compatibility_Graphical = new QButtonGroup(this); | ||
| 70 | compatibility_Graphical->addButton(ui->radioButton_Graphical_Major, 0); | ||
| 71 | compatibility_Graphical->addButton(ui->radioButton_Graphical_Minor, 1); | ||
| 72 | compatibility_Graphical->addButton(ui->radioButton_Graphical_No, 2); | ||
| 73 | |||
| 74 | QButtonGroup* compatibility_Audio = new QButtonGroup(this); | ||
| 75 | compatibility_Audio->addButton(ui->radioButton_Audio_Major, 0); | ||
| 76 | compatibility_Graphical->addButton(ui->radioButton_Audio_Minor, 1); | ||
| 77 | compatibility_Audio->addButton(ui->radioButton_Audio_No, 2); | ||
| 78 | |||
| 79 | const int compatiblity = static_cast<int>(CalculateCompatibility()); | ||
| 80 | |||
| 45 | switch ((static_cast<CompatDBPage>(currentId()))) { | 81 | switch ((static_cast<CompatDBPage>(currentId()))) { |
| 46 | case CompatDBPage::Selection: | 82 | case CompatDBPage::Intro: |
| 47 | if (compatibility->checkedId() == -1) { | 83 | break; |
| 84 | case CompatDBPage::GameBoot: | ||
| 85 | if (compatibility_GameBoot->checkedId() == -1) { | ||
| 86 | button(NextButton)->setEnabled(false); | ||
| 87 | } | ||
| 88 | break; | ||
| 89 | case CompatDBPage::GamePlay: | ||
| 90 | if (compatibility_Gameplay->checkedId() == -1) { | ||
| 91 | button(NextButton)->setEnabled(false); | ||
| 92 | } | ||
| 93 | break; | ||
| 94 | case CompatDBPage::Freeze: | ||
| 95 | if (compatibility_NoFreeze->checkedId() == -1) { | ||
| 96 | button(NextButton)->setEnabled(false); | ||
| 97 | } | ||
| 98 | break; | ||
| 99 | case CompatDBPage::Completion: | ||
| 100 | if (compatibility_Complete->checkedId() == -1) { | ||
| 101 | button(NextButton)->setEnabled(false); | ||
| 102 | } | ||
| 103 | break; | ||
| 104 | case CompatDBPage::Graphical: | ||
| 105 | if (compatibility_Graphical->checkedId() == -1) { | ||
| 106 | button(NextButton)->setEnabled(false); | ||
| 107 | } | ||
| 108 | break; | ||
| 109 | case CompatDBPage::Audio: | ||
| 110 | if (compatibility_Audio->checkedId() == -1) { | ||
| 48 | button(NextButton)->setEnabled(false); | 111 | button(NextButton)->setEnabled(false); |
| 49 | } | 112 | } |
| 50 | break; | 113 | break; |
| 51 | case CompatDBPage::Final: | 114 | case CompatDBPage::Final: |
| 52 | back(); | 115 | back(); |
| 53 | LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId()); | 116 | LOG_INFO(Frontend, "Compatibility Rating: {}", compatiblity); |
| 54 | telemetry_session.AddField(Common::Telemetry::FieldType::UserFeedback, "Compatibility", | 117 | telemetry_session.AddField(Common::Telemetry::FieldType::UserFeedback, "Compatibility", |
| 55 | compatibility->checkedId()); | 118 | compatiblity); |
| 56 | 119 | ||
| 57 | button(NextButton)->setEnabled(false); | 120 | button(NextButton)->setEnabled(false); |
| 58 | button(NextButton)->setText(tr("Submitting")); | 121 | button(NextButton)->setText(tr("Submitting")); |
| @@ -66,6 +129,66 @@ void CompatDB::Submit() { | |||
| 66 | } | 129 | } |
| 67 | } | 130 | } |
| 68 | 131 | ||
| 132 | int CompatDB::nextId() const { | ||
| 133 | switch ((static_cast<CompatDBPage>(currentId()))) { | ||
| 134 | case CompatDBPage::Intro: | ||
| 135 | return static_cast<int>(CompatDBPage::GameBoot); | ||
| 136 | case CompatDBPage::GameBoot: | ||
| 137 | if (ui->radioButton_GameBoot_No->isChecked()) { | ||
| 138 | return static_cast<int>(CompatDBPage::Final); | ||
| 139 | } | ||
| 140 | return static_cast<int>(CompatDBPage::GamePlay); | ||
| 141 | case CompatDBPage::GamePlay: | ||
| 142 | if (ui->radioButton_Gameplay_No->isChecked()) { | ||
| 143 | return static_cast<int>(CompatDBPage::Final); | ||
| 144 | } | ||
| 145 | return static_cast<int>(CompatDBPage::Freeze); | ||
| 146 | case CompatDBPage::Freeze: | ||
| 147 | if (ui->radioButton_NoFreeze_No->isChecked()) { | ||
| 148 | return static_cast<int>(CompatDBPage::Final); | ||
| 149 | } | ||
| 150 | return static_cast<int>(CompatDBPage::Completion); | ||
| 151 | case CompatDBPage::Completion: | ||
| 152 | if (ui->radioButton_Complete_No->isChecked()) { | ||
| 153 | return static_cast<int>(CompatDBPage::Final); | ||
| 154 | } | ||
| 155 | return static_cast<int>(CompatDBPage::Graphical); | ||
| 156 | case CompatDBPage::Graphical: | ||
| 157 | return static_cast<int>(CompatDBPage::Audio); | ||
| 158 | case CompatDBPage::Audio: | ||
| 159 | return static_cast<int>(CompatDBPage::Final); | ||
| 160 | case CompatDBPage::Final: | ||
| 161 | return -1; | ||
| 162 | default: | ||
| 163 | LOG_ERROR(Frontend, "Unexpected page: {}", currentId()); | ||
| 164 | return static_cast<int>(CompatDBPage::Intro); | ||
| 165 | } | ||
| 166 | } | ||
| 167 | |||
| 168 | CompatibilityStatus CompatDB::CalculateCompatibility() const { | ||
| 169 | if (ui->radioButton_GameBoot_No->isChecked()) { | ||
| 170 | return CompatibilityStatus::WontBoot; | ||
| 171 | } | ||
| 172 | |||
| 173 | if (ui->radioButton_Gameplay_No->isChecked()) { | ||
| 174 | return CompatibilityStatus::IntroMenu; | ||
| 175 | } | ||
| 176 | |||
| 177 | if (ui->radioButton_NoFreeze_No->isChecked() || ui->radioButton_Complete_No->isChecked()) { | ||
| 178 | return CompatibilityStatus::Ingame; | ||
| 179 | } | ||
| 180 | |||
| 181 | if (ui->radioButton_Graphical_Major->isChecked() || ui->radioButton_Audio_Major->isChecked()) { | ||
| 182 | return CompatibilityStatus::Ingame; | ||
| 183 | } | ||
| 184 | |||
| 185 | if (ui->radioButton_Graphical_Minor->isChecked() || ui->radioButton_Audio_Minor->isChecked()) { | ||
| 186 | return CompatibilityStatus::Playable; | ||
| 187 | } | ||
| 188 | |||
| 189 | return CompatibilityStatus::Perfect; | ||
| 190 | } | ||
| 191 | |||
| 69 | void CompatDB::OnTestcaseSubmitted() { | 192 | void CompatDB::OnTestcaseSubmitted() { |
| 70 | if (!testcase_watcher.result()) { | 193 | if (!testcase_watcher.result()) { |
| 71 | QMessageBox::critical(this, tr("Communication error"), | 194 | QMessageBox::critical(this, tr("Communication error"), |
diff --git a/src/yuzu/compatdb.h b/src/yuzu/compatdb.h index 3252fc47a..37e11278b 100644 --- a/src/yuzu/compatdb.h +++ b/src/yuzu/compatdb.h | |||
| @@ -12,12 +12,22 @@ namespace Ui { | |||
| 12 | class CompatDB; | 12 | class CompatDB; |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | enum class CompatibilityStatus { | ||
| 16 | Perfect = 0, | ||
| 17 | Playable = 1, | ||
| 18 | // Unused: Okay = 2, | ||
| 19 | Ingame = 3, | ||
| 20 | IntroMenu = 4, | ||
| 21 | WontBoot = 5, | ||
| 22 | }; | ||
| 23 | |||
| 15 | class CompatDB : public QWizard { | 24 | class CompatDB : public QWizard { |
| 16 | Q_OBJECT | 25 | Q_OBJECT |
| 17 | 26 | ||
| 18 | public: | 27 | public: |
| 19 | explicit CompatDB(Core::TelemetrySession& telemetry_session_, QWidget* parent = nullptr); | 28 | explicit CompatDB(Core::TelemetrySession& telemetry_session_, QWidget* parent = nullptr); |
| 20 | ~CompatDB(); | 29 | ~CompatDB(); |
| 30 | int nextId() const override; | ||
| 21 | 31 | ||
| 22 | private: | 32 | private: |
| 23 | QFutureWatcher<bool> testcase_watcher; | 33 | QFutureWatcher<bool> testcase_watcher; |
| @@ -25,6 +35,7 @@ private: | |||
| 25 | std::unique_ptr<Ui::CompatDB> ui; | 35 | std::unique_ptr<Ui::CompatDB> ui; |
| 26 | 36 | ||
| 27 | void Submit(); | 37 | void Submit(); |
| 38 | CompatibilityStatus CalculateCompatibility() const; | ||
| 28 | void OnTestcaseSubmitted(); | 39 | void OnTestcaseSubmitted(); |
| 29 | void EnableNext(); | 40 | void EnableNext(); |
| 30 | 41 | ||
diff --git a/src/yuzu/compatdb.ui b/src/yuzu/compatdb.ui index 3ca55eda6..d11669df2 100644 --- a/src/yuzu/compatdb.ui +++ b/src/yuzu/compatdb.ui | |||
| @@ -58,128 +58,311 @@ | |||
| 58 | </item> | 58 | </item> |
| 59 | </layout> | 59 | </layout> |
| 60 | </widget> | 60 | </widget> |
| 61 | <widget class="QWizardPage" name="wizard_Report"> | 61 | <widget class="QWizardPage" name="wizard_GameBoot"> |
| 62 | <property name="title"> | 62 | <property name="title"> |
| 63 | <string>Report Game Compatibility</string> | 63 | <string>Report Game Compatibility</string> |
| 64 | </property> | 64 | </property> |
| 65 | <attribute name="pageId"> | 65 | <attribute name="pageId"> |
| 66 | <string notr="true">1</string> | 66 | <string notr="true">1</string> |
| 67 | </attribute> | 67 | </attribute> |
| 68 | <layout class="QFormLayout" name="formLayout"> | 68 | <layout class="QFormLayout" name="formLayout1"> |
| 69 | <item row="0" column="0" colspan="2"> | ||
| 70 | <widget class="QLabel" name="lbl_Independent1"> | ||
| 71 | <property name="font"> | ||
| 72 | <font> | ||
| 73 | <pointsize>10</pointsize> | ||
| 74 | </font> | ||
| 75 | </property> | ||
| 76 | <property name="text"> | ||
| 77 | <string><html><head/><body><p>Does the game boot?</p></body></html></string> | ||
| 78 | </property> | ||
| 79 | <property name="wordWrap"> | ||
| 80 | <bool>true</bool> | ||
| 81 | </property> | ||
| 82 | </widget> | ||
| 83 | </item> | ||
| 84 | <item row="1" column="0" colspan="2"> | ||
| 85 | <spacer name="verticalSpacer1"> | ||
| 86 | <property name="orientation"> | ||
| 87 | <enum>Qt::Vertical</enum> | ||
| 88 | </property> | ||
| 89 | <property name="sizeHint" stdset="0"> | ||
| 90 | <size> | ||
| 91 | <width>20</width> | ||
| 92 | <height>0</height> | ||
| 93 | </size> | ||
| 94 | </property> | ||
| 95 | </spacer> | ||
| 96 | </item> | ||
| 69 | <item row="2" column="0"> | 97 | <item row="2" column="0"> |
| 70 | <widget class="QRadioButton" name="radioButton_Perfect"> | 98 | <widget class="QRadioButton" name="radioButton_GameBoot_Yes"> |
| 71 | <property name="text"> | 99 | <property name="text"> |
| 72 | <string>Perfect</string> | 100 | <string>Yes The game starts to output video or audio</string> |
| 73 | </property> | 101 | </property> |
| 74 | </widget> | 102 | </widget> |
| 75 | </item> | 103 | </item> |
| 76 | <item row="2" column="1"> | 104 | <item row="4" column="0"> |
| 77 | <widget class="QLabel" name="lbl_Perfect"> | 105 | <widget class="QRadioButton" name="radioButton_GameBoot_No"> |
| 78 | <property name="text"> | 106 | <property name="text"> |
| 79 | <string><html><head/><body><p>Game functions flawlessly with no audio or graphical glitches.</p></body></html></string> | 107 | <string>No The game doesn't get past the "Launching..." screen</string> |
| 80 | </property> | 108 | </property> |
| 81 | <property name="wordWrap"> | 109 | </widget> |
| 82 | <bool>true</bool> | 110 | </item> |
| 111 | </layout> | ||
| 112 | </widget> | ||
| 113 | <widget class="QWizardPage" name="wizard_GamePlay"> | ||
| 114 | <property name="title"> | ||
| 115 | <string>Report Game Compatibility</string> | ||
| 116 | </property> | ||
| 117 | <attribute name="pageId"> | ||
| 118 | <string notr="true">2</string> | ||
| 119 | </attribute> | ||
| 120 | <layout class="QFormLayout" name="formLayout2"> | ||
| 121 | <item row="2" column="0"> | ||
| 122 | <widget class="QRadioButton" name="radioButton_Gameplay_Yes"> | ||
| 123 | <property name="text"> | ||
| 124 | <string>Yes The game gets past the intro/menu and into gameplay</string> | ||
| 83 | </property> | 125 | </property> |
| 84 | </widget> | 126 | </widget> |
| 85 | </item> | 127 | </item> |
| 86 | <item row="4" column="0"> | 128 | <item row="4" column="0"> |
| 87 | <widget class="QRadioButton" name="radioButton_Great"> | 129 | <widget class="QRadioButton" name="radioButton_Gameplay_No"> |
| 88 | <property name="text"> | 130 | <property name="text"> |
| 89 | <string>Great</string> | 131 | <string>No The game crashes or freezes while loading or using the menu</string> |
| 90 | </property> | 132 | </property> |
| 91 | </widget> | 133 | </widget> |
| 92 | </item> | 134 | </item> |
| 93 | <item row="4" column="1"> | 135 | <item row="0" column="0" colspan="2"> |
| 94 | <widget class="QLabel" name="lbl_Great"> | 136 | <widget class="QLabel" name="lbl_Independent2"> |
| 137 | <property name="font"> | ||
| 138 | <font> | ||
| 139 | <pointsize>10</pointsize> | ||
| 140 | </font> | ||
| 141 | </property> | ||
| 95 | <property name="text"> | 142 | <property name="text"> |
| 96 | <string><html><head/><body><p>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.</p></body></html></string> | 143 | <string><html><head/><body><p>Does the game reach gameplay?</p></body></html></string> |
| 97 | </property> | 144 | </property> |
| 98 | <property name="wordWrap"> | 145 | <property name="wordWrap"> |
| 99 | <bool>true</bool> | 146 | <bool>true</bool> |
| 100 | </property> | 147 | </property> |
| 101 | </widget> | 148 | </widget> |
| 102 | </item> | 149 | </item> |
| 103 | <item row="5" column="0"> | 150 | <item row="1" column="0" colspan="2"> |
| 104 | <widget class="QRadioButton" name="radioButton_Okay"> | 151 | <spacer name="verticalSpacer2"> |
| 152 | <property name="orientation"> | ||
| 153 | <enum>Qt::Vertical</enum> | ||
| 154 | </property> | ||
| 155 | <property name="sizeHint" stdset="0"> | ||
| 156 | <size> | ||
| 157 | <width>20</width> | ||
| 158 | <height>0</height> | ||
| 159 | </size> | ||
| 160 | </property> | ||
| 161 | </spacer> | ||
| 162 | </item> | ||
| 163 | </layout> | ||
| 164 | </widget> | ||
| 165 | <widget class="QWizardPage" name="wizard_NoFreeze"> | ||
| 166 | <property name="title"> | ||
| 167 | <string>Report Game Compatibility</string> | ||
| 168 | </property> | ||
| 169 | <attribute name="pageId"> | ||
| 170 | <string notr="true">3</string> | ||
| 171 | </attribute> | ||
| 172 | <layout class="QFormLayout" name="formLayout3"> | ||
| 173 | <item row="2" column="0"> | ||
| 174 | <widget class="QRadioButton" name="radioButton_NoFreeze_Yes"> | ||
| 105 | <property name="text"> | 175 | <property name="text"> |
| 106 | <string>Okay</string> | 176 | <string>Yes The game works without crashes</string> |
| 107 | </property> | 177 | </property> |
| 108 | </widget> | 178 | </widget> |
| 109 | </item> | 179 | </item> |
| 110 | <item row="5" column="1"> | 180 | <item row="4" column="0"> |
| 111 | <widget class="QLabel" name="lbl_Okay"> | 181 | <widget class="QRadioButton" name="radioButton_NoFreeze_No"> |
| 182 | <property name="text"> | ||
| 183 | <string>No The game crashes or freezes during gameplay</string> | ||
| 184 | </property> | ||
| 185 | </widget> | ||
| 186 | </item> | ||
| 187 | <item row="0" column="0" colspan="2"> | ||
| 188 | <widget class="QLabel" name="lbl_Independent3"> | ||
| 189 | <property name="font"> | ||
| 190 | <font> | ||
| 191 | <pointsize>10</pointsize> | ||
| 192 | </font> | ||
| 193 | </property> | ||
| 112 | <property name="text"> | 194 | <property name="text"> |
| 113 | <string><html><head/><body><p>Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.</p></body></html></string> | 195 | <string><html><head/><body><p>Does the game work without crashing, freezing or locking up during gameplay?</p></body></html></string> |
| 114 | </property> | 196 | </property> |
| 115 | <property name="wordWrap"> | 197 | <property name="wordWrap"> |
| 116 | <bool>true</bool> | 198 | <bool>true</bool> |
| 117 | </property> | 199 | </property> |
| 118 | </widget> | 200 | </widget> |
| 119 | </item> | 201 | </item> |
| 120 | <item row="6" column="0"> | 202 | <item row="1" column="0" colspan="2"> |
| 121 | <widget class="QRadioButton" name="radioButton_Bad"> | 203 | <spacer name="verticalSpacer3"> |
| 204 | <property name="orientation"> | ||
| 205 | <enum>Qt::Vertical</enum> | ||
| 206 | </property> | ||
| 207 | <property name="sizeHint" stdset="0"> | ||
| 208 | <size> | ||
| 209 | <width>20</width> | ||
| 210 | <height>0</height> | ||
| 211 | </size> | ||
| 212 | </property> | ||
| 213 | </spacer> | ||
| 214 | </item> | ||
| 215 | </layout> | ||
| 216 | </widget> | ||
| 217 | <widget class="QWizardPage" name="wizard_Complete"> | ||
| 218 | <property name="title"> | ||
| 219 | <string>Report Game Compatibility</string> | ||
| 220 | </property> | ||
| 221 | <attribute name="pageId"> | ||
| 222 | <string notr="true">4</string> | ||
| 223 | </attribute> | ||
| 224 | <layout class="QFormLayout" name="formLayout4"> | ||
| 225 | <item row="2" column="0"> | ||
| 226 | <widget class="QRadioButton" name="radioButton_Complete_Yes"> | ||
| 122 | <property name="text"> | 227 | <property name="text"> |
| 123 | <string>Bad</string> | 228 | <string>Yes The game can be finished without any workarounds</string> |
| 124 | </property> | 229 | </property> |
| 125 | </widget> | 230 | </widget> |
| 126 | </item> | 231 | </item> |
| 127 | <item row="6" column="1"> | 232 | <item row="4" column="0"> |
| 128 | <widget class="QLabel" name="lbl_Bad"> | 233 | <widget class="QRadioButton" name="radioButton_Complete_No"> |
| 234 | <property name="text"> | ||
| 235 | <string>No The game can't progress past a certain area</string> | ||
| 236 | </property> | ||
| 237 | </widget> | ||
| 238 | </item> | ||
| 239 | <item row="0" column="0" colspan="2"> | ||
| 240 | <widget class="QLabel" name="lbl_Independent4"> | ||
| 241 | <property name="font"> | ||
| 242 | <font> | ||
| 243 | <pointsize>10</pointsize> | ||
| 244 | </font> | ||
| 245 | </property> | ||
| 129 | <property name="text"> | 246 | <property name="text"> |
| 130 | <string><html><head/><body><p>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.</p></body></html></string> | 247 | <string><html><head/><body><p>Is the game completely playable from start to finish?</p></body></html></string> |
| 131 | </property> | 248 | </property> |
| 132 | <property name="wordWrap"> | 249 | <property name="wordWrap"> |
| 133 | <bool>true</bool> | 250 | <bool>true</bool> |
| 134 | </property> | 251 | </property> |
| 135 | </widget> | 252 | </widget> |
| 136 | </item> | 253 | </item> |
| 137 | <item row="7" column="0"> | 254 | <item row="1" column="0" colspan="2"> |
| 138 | <widget class="QRadioButton" name="radioButton_IntroMenu"> | 255 | <spacer name="verticalSpacer4"> |
| 256 | <property name="orientation"> | ||
| 257 | <enum>Qt::Vertical</enum> | ||
| 258 | </property> | ||
| 259 | <property name="sizeHint" stdset="0"> | ||
| 260 | <size> | ||
| 261 | <width>20</width> | ||
| 262 | <height>0</height> | ||
| 263 | </size> | ||
| 264 | </property> | ||
| 265 | </spacer> | ||
| 266 | </item> | ||
| 267 | </layout> | ||
| 268 | </widget> | ||
| 269 | <widget class="QWizardPage" name="wizard_Graphical"> | ||
| 270 | <property name="title"> | ||
| 271 | <string>Report Game Compatibility</string> | ||
| 272 | </property> | ||
| 273 | <attribute name="pageId"> | ||
| 274 | <string notr="true">5</string> | ||
| 275 | </attribute> | ||
| 276 | <layout class="QFormLayout" name="formLayout5"> | ||
| 277 | <item row="2" column="0"> | ||
| 278 | <widget class="QRadioButton" name="radioButton_Graphical_Major"> | ||
| 279 | <property name="text"> | ||
| 280 | <string>Major The game has major graphical errors</string> | ||
| 281 | </property> | ||
| 282 | </widget> | ||
| 283 | </item> | ||
| 284 | <item row="4" column="0"> | ||
| 285 | <widget class="QRadioButton" name="radioButton_Graphical_Minor"> | ||
| 139 | <property name="text"> | 286 | <property name="text"> |
| 140 | <string>Intro/Menu</string> | 287 | <string>Minor The game has minor graphical errors</string> |
| 141 | </property> | 288 | </property> |
| 142 | </widget> | 289 | </widget> |
| 143 | </item> | 290 | </item> |
| 144 | <item row="7" column="1"> | 291 | <item row="6" column="0"> |
| 145 | <widget class="QLabel" name="lbl_IntroMenu"> | 292 | <widget class="QRadioButton" name="radioButton_Graphical_No"> |
| 293 | <property name="text"> | ||
| 294 | <string>None Everything is rendered as it looks on the Nintendo Switch</string> | ||
| 295 | </property> | ||
| 296 | </widget> | ||
| 297 | </item> | ||
| 298 | <item row="0" column="0" colspan="2"> | ||
| 299 | <widget class="QLabel" name="lbl_Independent5"> | ||
| 300 | <property name="font"> | ||
| 301 | <font> | ||
| 302 | <pointsize>10</pointsize> | ||
| 303 | </font> | ||
| 304 | </property> | ||
| 146 | <property name="text"> | 305 | <property name="text"> |
| 147 | <string><html><head/><body><p>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.</p></body></html></string> | 306 | <string><html><head/><body><p>Does the game have any graphical glitches?</p></body></html></string> |
| 148 | </property> | 307 | </property> |
| 149 | <property name="wordWrap"> | 308 | <property name="wordWrap"> |
| 150 | <bool>true</bool> | 309 | <bool>true</bool> |
| 151 | </property> | 310 | </property> |
| 152 | </widget> | 311 | </widget> |
| 153 | </item> | 312 | </item> |
| 154 | <item row="8" column="0"> | 313 | <item row="1" column="0" colspan="2"> |
| 155 | <widget class="QRadioButton" name="radioButton_WontBoot"> | 314 | <spacer name="verticalSpacer5"> |
| 156 | <property name="text"> | 315 | <property name="orientation"> |
| 157 | <string>Won't Boot</string> | 316 | <enum>Qt::Vertical</enum> |
| 158 | </property> | 317 | </property> |
| 159 | <property name="checkable"> | 318 | <property name="sizeHint" stdset="0"> |
| 160 | <bool>true</bool> | 319 | <size> |
| 320 | <width>20</width> | ||
| 321 | <height>0</height> | ||
| 322 | </size> | ||
| 161 | </property> | 323 | </property> |
| 162 | <property name="checked"> | 324 | </spacer> |
| 163 | <bool>false</bool> | 325 | </item> |
| 326 | </layout> | ||
| 327 | </widget> | ||
| 328 | <widget class="QWizardPage" name="wizard_Audio"> | ||
| 329 | <property name="title"> | ||
| 330 | <string>Report Game Compatibility</string> | ||
| 331 | </property> | ||
| 332 | <attribute name="pageId"> | ||
| 333 | <string notr="true">6</string> | ||
| 334 | </attribute> | ||
| 335 | <layout class="QFormLayout" name="formLayout6"> | ||
| 336 | <item row="2" column="0"> | ||
| 337 | <widget class="QRadioButton" name="radioButton_Audio_Major"> | ||
| 338 | <property name="text"> | ||
| 339 | <string>Major The game has major audio errors</string> | ||
| 340 | </property> | ||
| 341 | </widget> | ||
| 342 | </item> | ||
| 343 | <item row="4" column="0"> | ||
| 344 | <widget class="QRadioButton" name="radioButton_Audio_Minor"> | ||
| 345 | <property name="text"> | ||
| 346 | <string>Minor The game has minor audio errors</string> | ||
| 164 | </property> | 347 | </property> |
| 165 | </widget> | 348 | </widget> |
| 166 | </item> | 349 | </item> |
| 167 | <item row="8" column="1"> | 350 | <item row="6" column="0"> |
| 168 | <widget class="QLabel" name="lbl_WontBoot"> | 351 | <widget class="QRadioButton" name="radioButton_Audio_No"> |
| 169 | <property name="text"> | 352 | <property name="text"> |
| 170 | <string><html><head/><body><p>The game crashes when attempting to startup.</p></body></html></string> | 353 | <string>None Audio is played perfectly</string> |
| 171 | </property> | 354 | </property> |
| 172 | </widget> | 355 | </widget> |
| 173 | </item> | 356 | </item> |
| 174 | <item row="0" column="0" colspan="2"> | 357 | <item row="0" column="0" colspan="2"> |
| 175 | <widget class="QLabel" name="lbl_Independent"> | 358 | <widget class="QLabel" name="lbl_Independent6"> |
| 176 | <property name="font"> | 359 | <property name="font"> |
| 177 | <font> | 360 | <font> |
| 178 | <pointsize>10</pointsize> | 361 | <pointsize>10</pointsize> |
| 179 | </font> | 362 | </font> |
| 180 | </property> | 363 | </property> |
| 181 | <property name="text"> | 364 | <property name="text"> |
| 182 | <string><html><head/><body><p>Independent of speed or performance, how well does this game play from start to finish on this version of yuzu?</p></body></html></string> | 365 | <string><html><head/><body><p>Does the game have any audio glitches / missing effects?</p></body></html></string> |
| 183 | </property> | 366 | </property> |
| 184 | <property name="wordWrap"> | 367 | <property name="wordWrap"> |
| 185 | <bool>true</bool> | 368 | <bool>true</bool> |
| @@ -187,7 +370,7 @@ | |||
| 187 | </widget> | 370 | </widget> |
| 188 | </item> | 371 | </item> |
| 189 | <item row="1" column="0" colspan="2"> | 372 | <item row="1" column="0" colspan="2"> |
| 190 | <spacer name="verticalSpacer"> | 373 | <spacer name="verticalSpacer6"> |
| 191 | <property name="orientation"> | 374 | <property name="orientation"> |
| 192 | <enum>Qt::Vertical</enum> | 375 | <enum>Qt::Vertical</enum> |
| 193 | </property> | 376 | </property> |
| @@ -206,7 +389,7 @@ | |||
| 206 | <string>Thank you for your submission!</string> | 389 | <string>Thank you for your submission!</string> |
| 207 | </property> | 390 | </property> |
| 208 | <attribute name="pageId"> | 391 | <attribute name="pageId"> |
| 209 | <string notr="true">2</string> | 392 | <string notr="true">7</string> |
| 210 | </attribute> | 393 | </attribute> |
| 211 | </widget> | 394 | </widget> |
| 212 | </widget> | 395 | </widget> |
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index 6198d1e4e..1800f090f 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h | |||
| @@ -145,12 +145,14 @@ public: | |||
| 145 | const char* tooltip; | 145 | const char* tooltip; |
| 146 | }; | 146 | }; |
| 147 | // clang-format off | 147 | // clang-format off |
| 148 | const auto ingame_status = | ||
| 149 | CompatStatus{QStringLiteral("#f2d624"), QT_TR_NOOP("Ingame"), QT_TR_NOOP("Game starts, but crashes or major glitches prevent it from being completed.")}; | ||
| 148 | static const std::map<QString, CompatStatus> status_data = { | 150 | static const std::map<QString, CompatStatus> status_data = { |
| 149 | {QStringLiteral("0"), {QStringLiteral("#5c93ed"), QT_TR_NOOP("Perfect"), QT_TR_NOOP("Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without\nany workarounds needed.")}}, | 151 | {QStringLiteral("0"), {QStringLiteral("#5c93ed"), QT_TR_NOOP("Perfect"), QT_TR_NOOP("Game can be played without issues.")}}, |
| 150 | {QStringLiteral("1"), {QStringLiteral("#47d35c"), QT_TR_NOOP("Great"), QT_TR_NOOP("Game functions with minor graphical or audio glitches and is playable from start to finish. May require some\nworkarounds.")}}, | 152 | {QStringLiteral("1"), {QStringLiteral("#47d35c"), QT_TR_NOOP("Playable"), QT_TR_NOOP("Game functions with minor graphical or audio glitches and is playable from start to finish.")}}, |
| 151 | {QStringLiteral("2"), {QStringLiteral("#94b242"), QT_TR_NOOP("Okay"), QT_TR_NOOP("Game functions with major graphical or audio glitches, but game is playable from start to finish with\nworkarounds.")}}, | 153 | {QStringLiteral("2"), ingame_status}, |
| 152 | {QStringLiteral("3"), {QStringLiteral("#f2d624"), QT_TR_NOOP("Bad"), QT_TR_NOOP("Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches\neven with workarounds.")}}, | 154 | {QStringLiteral("3"), ingame_status}, // Fallback for the removed "Okay" category |
| 153 | {QStringLiteral("4"), {QStringLiteral("#FF0000"), QT_TR_NOOP("Intro/Menu"), QT_TR_NOOP("Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start\nScreen.")}}, | 155 | {QStringLiteral("4"), {QStringLiteral("#FF0000"), QT_TR_NOOP("Intro/Menu"), QT_TR_NOOP("Game loads, but is unable to progress past the Start Screen.")}}, |
| 154 | {QStringLiteral("5"), {QStringLiteral("#828282"), QT_TR_NOOP("Won't Boot"), QT_TR_NOOP("The game crashes when attempting to startup.")}}, | 156 | {QStringLiteral("5"), {QStringLiteral("#828282"), QT_TR_NOOP("Won't Boot"), QT_TR_NOOP("The game crashes when attempting to startup.")}}, |
| 155 | {QStringLiteral("99"), {QStringLiteral("#000000"), QT_TR_NOOP("Not Tested"), QT_TR_NOOP("The game has not yet been tested.")}}, | 157 | {QStringLiteral("99"), {QStringLiteral("#000000"), QT_TR_NOOP("Not Tested"), QT_TR_NOOP("The game has not yet been tested.")}}, |
| 156 | }; | 158 | }; |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 59e56633a..032ff1cbc 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -342,6 +342,7 @@ GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan | |||
| 342 | const auto override_build = | 342 | const auto override_build = |
| 343 | fmt::format(fmt::runtime(std::string(Common::g_title_bar_format_idle)), build_id); | 343 | fmt::format(fmt::runtime(std::string(Common::g_title_bar_format_idle)), build_id); |
| 344 | const auto yuzu_build_version = override_build.empty() ? yuzu_build : override_build; | 344 | const auto yuzu_build_version = override_build.empty() ? yuzu_build : override_build; |
| 345 | const auto processor_count = std::thread::hardware_concurrency(); | ||
| 345 | 346 | ||
| 346 | LOG_INFO(Frontend, "yuzu Version: {}", yuzu_build_version); | 347 | LOG_INFO(Frontend, "yuzu Version: {}", yuzu_build_version); |
| 347 | LogRuntimes(); | 348 | LogRuntimes(); |
| @@ -361,6 +362,11 @@ GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan | |||
| 361 | } | 362 | } |
| 362 | LOG_INFO(Frontend, "Host CPU: {}", cpu_string); | 363 | LOG_INFO(Frontend, "Host CPU: {}", cpu_string); |
| 363 | #endif | 364 | #endif |
| 365 | |||
| 366 | if (std::optional<int> processor_core = Common::GetProcessorCount()) { | ||
| 367 | LOG_INFO(Frontend, "Host CPU Cores: {}", *processor_core); | ||
| 368 | } | ||
| 369 | LOG_INFO(Frontend, "Host CPU Threads: {}", processor_count); | ||
| 364 | LOG_INFO(Frontend, "Host OS: {}", PrettyProductName().toStdString()); | 370 | LOG_INFO(Frontend, "Host OS: {}", PrettyProductName().toStdString()); |
| 365 | LOG_INFO(Frontend, "Host RAM: {:.2f} GiB", | 371 | LOG_INFO(Frontend, "Host RAM: {:.2f} GiB", |
| 366 | Common::GetMemInfo().TotalPhysicalMemory / f64{1_GiB}); | 372 | Common::GetMemInfo().TotalPhysicalMemory / f64{1_GiB}); |
| @@ -2018,38 +2024,50 @@ static bool RomFSRawCopy(QProgressDialog& dialog, const FileSys::VirtualDir& src | |||
| 2018 | return true; | 2024 | return true; |
| 2019 | } | 2025 | } |
| 2020 | 2026 | ||
| 2027 | QString GMainWindow::GetGameListErrorRemoving(InstalledEntryType type) const { | ||
| 2028 | switch (type) { | ||
| 2029 | case InstalledEntryType::Game: | ||
| 2030 | return tr("Error Removing Contents"); | ||
| 2031 | case InstalledEntryType::Update: | ||
| 2032 | return tr("Error Removing Update"); | ||
| 2033 | case InstalledEntryType::AddOnContent: | ||
| 2034 | return tr("Error Removing DLC"); | ||
| 2035 | default: | ||
| 2036 | return QStringLiteral("Error Removing <Invalid Type>"); | ||
| 2037 | } | ||
| 2038 | } | ||
| 2021 | void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type) { | 2039 | void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type) { |
| 2022 | const QString entry_type = [type] { | 2040 | const QString entry_question = [type] { |
| 2023 | switch (type) { | 2041 | switch (type) { |
| 2024 | case InstalledEntryType::Game: | 2042 | case InstalledEntryType::Game: |
| 2025 | return tr("Contents"); | 2043 | return tr("Remove Installed Game Contents?"); |
| 2026 | case InstalledEntryType::Update: | 2044 | case InstalledEntryType::Update: |
| 2027 | return tr("Update"); | 2045 | return tr("Remove Installed Game Update?"); |
| 2028 | case InstalledEntryType::AddOnContent: | 2046 | case InstalledEntryType::AddOnContent: |
| 2029 | return tr("DLC"); | 2047 | return tr("Remove Installed Game DLC?"); |
| 2030 | default: | 2048 | default: |
| 2031 | return QString{}; | 2049 | return QStringLiteral("Remove Installed Game <Invalid Type>?"); |
| 2032 | } | 2050 | } |
| 2033 | }(); | 2051 | }(); |
| 2034 | 2052 | ||
| 2035 | if (QMessageBox::question( | 2053 | if (QMessageBox::question(this, tr("Remove Entry"), entry_question, |
| 2036 | this, tr("Remove Entry"), tr("Remove Installed Game %1?").arg(entry_type), | 2054 | QMessageBox::Yes | QMessageBox::No, |
| 2037 | QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes) { | 2055 | QMessageBox::No) != QMessageBox::Yes) { |
| 2038 | return; | 2056 | return; |
| 2039 | } | 2057 | } |
| 2040 | 2058 | ||
| 2041 | switch (type) { | 2059 | switch (type) { |
| 2042 | case InstalledEntryType::Game: | 2060 | case InstalledEntryType::Game: |
| 2043 | RemoveBaseContent(program_id, entry_type); | 2061 | RemoveBaseContent(program_id, type); |
| 2044 | [[fallthrough]]; | 2062 | [[fallthrough]]; |
| 2045 | case InstalledEntryType::Update: | 2063 | case InstalledEntryType::Update: |
| 2046 | RemoveUpdateContent(program_id, entry_type); | 2064 | RemoveUpdateContent(program_id, type); |
| 2047 | if (type != InstalledEntryType::Game) { | 2065 | if (type != InstalledEntryType::Game) { |
| 2048 | break; | 2066 | break; |
| 2049 | } | 2067 | } |
| 2050 | [[fallthrough]]; | 2068 | [[fallthrough]]; |
| 2051 | case InstalledEntryType::AddOnContent: | 2069 | case InstalledEntryType::AddOnContent: |
| 2052 | RemoveAddOnContent(program_id, entry_type); | 2070 | RemoveAddOnContent(program_id, type); |
| 2053 | break; | 2071 | break; |
| 2054 | } | 2072 | } |
| 2055 | Common::FS::RemoveDirRecursively(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / | 2073 | Common::FS::RemoveDirRecursively(Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / |
| @@ -2057,7 +2075,7 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT | |||
| 2057 | game_list->PopulateAsync(UISettings::values.game_dirs); | 2075 | game_list->PopulateAsync(UISettings::values.game_dirs); |
| 2058 | } | 2076 | } |
| 2059 | 2077 | ||
| 2060 | void GMainWindow::RemoveBaseContent(u64 program_id, const QString& entry_type) { | 2078 | void GMainWindow::RemoveBaseContent(u64 program_id, InstalledEntryType type) { |
| 2061 | const auto& fs_controller = system->GetFileSystemController(); | 2079 | const auto& fs_controller = system->GetFileSystemController(); |
| 2062 | const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(program_id) || | 2080 | const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(program_id) || |
| 2063 | fs_controller.GetSDMCContents()->RemoveExistingEntry(program_id); | 2081 | fs_controller.GetSDMCContents()->RemoveExistingEntry(program_id); |
| @@ -2067,12 +2085,12 @@ void GMainWindow::RemoveBaseContent(u64 program_id, const QString& entry_type) { | |||
| 2067 | tr("Successfully removed the installed base game.")); | 2085 | tr("Successfully removed the installed base game.")); |
| 2068 | } else { | 2086 | } else { |
| 2069 | QMessageBox::warning( | 2087 | QMessageBox::warning( |
| 2070 | this, tr("Error Removing %1").arg(entry_type), | 2088 | this, GetGameListErrorRemoving(type), |
| 2071 | tr("The base game is not installed in the NAND and cannot be removed.")); | 2089 | tr("The base game is not installed in the NAND and cannot be removed.")); |
| 2072 | } | 2090 | } |
| 2073 | } | 2091 | } |
| 2074 | 2092 | ||
| 2075 | void GMainWindow::RemoveUpdateContent(u64 program_id, const QString& entry_type) { | 2093 | void GMainWindow::RemoveUpdateContent(u64 program_id, InstalledEntryType type) { |
| 2076 | const auto update_id = program_id | 0x800; | 2094 | const auto update_id = program_id | 0x800; |
| 2077 | const auto& fs_controller = system->GetFileSystemController(); | 2095 | const auto& fs_controller = system->GetFileSystemController(); |
| 2078 | const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(update_id) || | 2096 | const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(update_id) || |
| @@ -2082,12 +2100,12 @@ void GMainWindow::RemoveUpdateContent(u64 program_id, const QString& entry_type) | |||
| 2082 | QMessageBox::information(this, tr("Successfully Removed"), | 2100 | QMessageBox::information(this, tr("Successfully Removed"), |
| 2083 | tr("Successfully removed the installed update.")); | 2101 | tr("Successfully removed the installed update.")); |
| 2084 | } else { | 2102 | } else { |
| 2085 | QMessageBox::warning(this, tr("Error Removing %1").arg(entry_type), | 2103 | QMessageBox::warning(this, GetGameListErrorRemoving(type), |
| 2086 | tr("There is no update installed for this title.")); | 2104 | tr("There is no update installed for this title.")); |
| 2087 | } | 2105 | } |
| 2088 | } | 2106 | } |
| 2089 | 2107 | ||
| 2090 | void GMainWindow::RemoveAddOnContent(u64 program_id, const QString& entry_type) { | 2108 | void GMainWindow::RemoveAddOnContent(u64 program_id, InstalledEntryType type) { |
| 2091 | u32 count{}; | 2109 | u32 count{}; |
| 2092 | const auto& fs_controller = system->GetFileSystemController(); | 2110 | const auto& fs_controller = system->GetFileSystemController(); |
| 2093 | const auto dlc_entries = system->GetContentProvider().ListEntriesFilter( | 2111 | const auto dlc_entries = system->GetContentProvider().ListEntriesFilter( |
| @@ -2105,7 +2123,7 @@ void GMainWindow::RemoveAddOnContent(u64 program_id, const QString& entry_type) | |||
| 2105 | } | 2123 | } |
| 2106 | 2124 | ||
| 2107 | if (count == 0) { | 2125 | if (count == 0) { |
| 2108 | QMessageBox::warning(this, tr("Error Removing %1").arg(entry_type), | 2126 | QMessageBox::warning(this, GetGameListErrorRemoving(type), |
| 2109 | tr("There are no DLC installed for this title.")); | 2127 | tr("There are no DLC installed for this title.")); |
| 2110 | return; | 2128 | return; |
| 2111 | } | 2129 | } |
| @@ -2803,6 +2821,20 @@ void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_tex | |||
| 2803 | } | 2821 | } |
| 2804 | 2822 | ||
| 2805 | void GMainWindow::OnMenuReportCompatibility() { | 2823 | void GMainWindow::OnMenuReportCompatibility() { |
| 2824 | const auto& caps = Common::GetCPUCaps(); | ||
| 2825 | const bool has_fma = caps.fma || caps.fma4; | ||
| 2826 | const auto processor_count = std::thread::hardware_concurrency(); | ||
| 2827 | const bool has_4threads = processor_count == 0 || processor_count >= 4; | ||
| 2828 | const bool has_8gb_ram = Common::GetMemInfo().TotalPhysicalMemory >= 8_GiB; | ||
| 2829 | const bool has_broken_vulkan = UISettings::values.has_broken_vulkan; | ||
| 2830 | |||
| 2831 | if (!has_fma || !has_4threads || !has_8gb_ram || has_broken_vulkan) { | ||
| 2832 | QMessageBox::critical(this, tr("Hardware requirements not met"), | ||
| 2833 | tr("Your system does not meet the recommended hardware requirements. " | ||
| 2834 | "Compatibility reporting has been disabled.")); | ||
| 2835 | return; | ||
| 2836 | } | ||
| 2837 | |||
| 2806 | if (!Settings::values.yuzu_token.GetValue().empty() && | 2838 | if (!Settings::values.yuzu_token.GetValue().empty() && |
| 2807 | !Settings::values.yuzu_username.GetValue().empty()) { | 2839 | !Settings::values.yuzu_username.GetValue().empty()) { |
| 2808 | CompatDB compatdb{system->TelemetrySession(), this}; | 2840 | CompatDB compatdb{system->TelemetrySession(), this}; |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 150ada84c..b73f550dd 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -324,9 +324,10 @@ private slots: | |||
| 324 | void OnMouseActivity(); | 324 | void OnMouseActivity(); |
| 325 | 325 | ||
| 326 | private: | 326 | private: |
| 327 | void RemoveBaseContent(u64 program_id, const QString& entry_type); | 327 | QString GetGameListErrorRemoving(InstalledEntryType type) const; |
| 328 | void RemoveUpdateContent(u64 program_id, const QString& entry_type); | 328 | void RemoveBaseContent(u64 program_id, InstalledEntryType type); |
| 329 | void RemoveAddOnContent(u64 program_id, const QString& entry_type); | 329 | void RemoveUpdateContent(u64 program_id, InstalledEntryType type); |
| 330 | void RemoveAddOnContent(u64 program_id, InstalledEntryType type); | ||
| 330 | void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target); | 331 | void RemoveTransferableShaderCache(u64 program_id, GameListRemoveTarget target); |
| 331 | void RemoveAllTransferableShaderCaches(u64 program_id); | 332 | void RemoveAllTransferableShaderCaches(u64 program_id); |
| 332 | void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); | 333 | void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); |