diff options
35 files changed, 460 insertions, 156 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index f26a0c6b8..91ec50bef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -477,8 +477,8 @@ if (APPLE) | |||
| 477 | find_library(COCOA_LIBRARY Cocoa) | 477 | find_library(COCOA_LIBRARY Cocoa) |
| 478 | set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY}) | 478 | set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY}) |
| 479 | elseif (WIN32) | 479 | elseif (WIN32) |
| 480 | # WSAPoll and SHGetKnownFolderPath (AppData/Roaming) didn't exist before WinNT 6.x (Vista) | 480 | # Target Windows 10 |
| 481 | add_definitions(-D_WIN32_WINNT=0x0600 -DWINVER=0x0600) | 481 | add_definitions(-D_WIN32_WINNT=0x0A00 -DWINVER=0x0A00) |
| 482 | set(PLATFORM_LIBRARIES winmm ws2_32 iphlpapi) | 482 | set(PLATFORM_LIBRARIES winmm ws2_32 iphlpapi) |
| 483 | if (MINGW) | 483 | if (MINGW) |
| 484 | # PSAPI is the Process Status API | 484 | # PSAPI is the Process Status API |
diff --git a/dist/yuzu.manifest b/dist/yuzu.manifest index 10a8df9b5..f2c8639a2 100644 --- a/dist/yuzu.manifest +++ b/dist/yuzu.manifest | |||
| @@ -36,12 +36,6 @@ SPDX-License-Identifier: GPL-2.0-or-later | |||
| 36 | <application> | 36 | <application> |
| 37 | <!-- Windows 10 --> | 37 | <!-- Windows 10 --> |
| 38 | <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> | 38 | <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> |
| 39 | <!-- Windows 8.1 --> | ||
| 40 | <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> | ||
| 41 | <!-- Windows 8 --> | ||
| 42 | <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> | ||
| 43 | <!-- Windows 7 --> | ||
| 44 | <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> | ||
| 45 | </application> | 39 | </application> |
| 46 | </compatibility> | 40 | </compatibility> |
| 47 | <trustInfo | 41 | <trustInfo |
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 56b247ac4..61ab68864 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -91,6 +91,7 @@ add_library(common STATIC | |||
| 91 | multi_level_page_table.h | 91 | multi_level_page_table.h |
| 92 | nvidia_flags.cpp | 92 | nvidia_flags.cpp |
| 93 | nvidia_flags.h | 93 | nvidia_flags.h |
| 94 | overflow.h | ||
| 94 | page_table.cpp | 95 | page_table.cpp |
| 95 | page_table.h | 96 | page_table.h |
| 96 | param_package.cpp | 97 | param_package.cpp |
| @@ -113,6 +114,8 @@ add_library(common STATIC | |||
| 113 | socket_types.h | 114 | socket_types.h |
| 114 | spin_lock.cpp | 115 | spin_lock.cpp |
| 115 | spin_lock.h | 116 | spin_lock.h |
| 117 | steady_clock.cpp | ||
| 118 | steady_clock.h | ||
| 116 | stream.cpp | 119 | stream.cpp |
| 117 | stream.h | 120 | stream.h |
| 118 | string_util.cpp | 121 | string_util.cpp |
| @@ -142,6 +145,14 @@ add_library(common STATIC | |||
| 142 | zstd_compression.h | 145 | zstd_compression.h |
| 143 | ) | 146 | ) |
| 144 | 147 | ||
| 148 | if (WIN32) | ||
| 149 | target_sources(common PRIVATE | ||
| 150 | windows/timer_resolution.cpp | ||
| 151 | windows/timer_resolution.h | ||
| 152 | ) | ||
| 153 | target_link_libraries(common PRIVATE ntdll) | ||
| 154 | endif() | ||
| 155 | |||
| 145 | if(ARCHITECTURE_x86_64) | 156 | if(ARCHITECTURE_x86_64) |
| 146 | target_sources(common | 157 | target_sources(common |
| 147 | PRIVATE | 158 | PRIVATE |
diff --git a/src/common/bit_cast.h b/src/common/bit_cast.h index 535148b4d..c6110c542 100644 --- a/src/common/bit_cast.h +++ b/src/common/bit_cast.h | |||
| @@ -3,19 +3,21 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <cstring> | 6 | #include <version> |
| 7 | #include <type_traits> | 7 | |
| 8 | #ifdef __cpp_lib_bit_cast | ||
| 9 | #include <bit> | ||
| 10 | #endif | ||
| 8 | 11 | ||
| 9 | namespace Common { | 12 | namespace Common { |
| 10 | 13 | ||
| 11 | template <typename To, typename From> | 14 | template <typename To, typename From> |
| 12 | [[nodiscard]] std::enable_if_t<sizeof(To) == sizeof(From) && std::is_trivially_copyable_v<From> && | 15 | constexpr inline To BitCast(const From& from) { |
| 13 | std::is_trivially_copyable_v<To>, | 16 | #ifdef __cpp_lib_bit_cast |
| 14 | To> | 17 | return std::bit_cast<To>(from); |
| 15 | BitCast(const From& src) noexcept { | 18 | #else |
| 16 | To dst; | 19 | return __builtin_bit_cast(To, from); |
| 17 | std::memcpy(&dst, &src, sizeof(To)); | 20 | #endif |
| 18 | return dst; | ||
| 19 | } | 21 | } |
| 20 | 22 | ||
| 21 | } // namespace Common | 23 | } // namespace Common |
diff --git a/src/common/input.h b/src/common/input.h index b5748a6c8..98e934685 100644 --- a/src/common/input.h +++ b/src/common/input.h | |||
| @@ -46,7 +46,7 @@ enum class PollingMode { | |||
| 46 | // Constant polling of buttons, analogs and motion data | 46 | // Constant polling of buttons, analogs and motion data |
| 47 | Active, | 47 | Active, |
| 48 | // Only update on button change, digital analogs | 48 | // Only update on button change, digital analogs |
| 49 | Pasive, | 49 | Passive, |
| 50 | // Enable near field communication polling | 50 | // Enable near field communication polling |
| 51 | NFC, | 51 | NFC, |
| 52 | // Enable infrared camera polling | 52 | // Enable infrared camera polling |
diff --git a/src/common/overflow.h b/src/common/overflow.h new file mode 100644 index 000000000..44d8e7e73 --- /dev/null +++ b/src/common/overflow.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <type_traits> | ||
| 7 | #include "bit_cast.h" | ||
| 8 | |||
| 9 | namespace Common { | ||
| 10 | |||
| 11 | template <typename T> | ||
| 12 | requires(std::is_integral_v<T> && std::is_signed_v<T>) | ||
| 13 | inline T WrappingAdd(T lhs, T rhs) { | ||
| 14 | using U = std::make_unsigned_t<T>; | ||
| 15 | |||
| 16 | U lhs_u = BitCast<U>(lhs); | ||
| 17 | U rhs_u = BitCast<U>(rhs); | ||
| 18 | |||
| 19 | return BitCast<T>(lhs_u + rhs_u); | ||
| 20 | } | ||
| 21 | |||
| 22 | } // namespace Common | ||
diff --git a/src/common/steady_clock.cpp b/src/common/steady_clock.cpp new file mode 100644 index 000000000..0d5908aa7 --- /dev/null +++ b/src/common/steady_clock.cpp | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #if defined(_WIN32) | ||
| 5 | #include <windows.h> | ||
| 6 | #else | ||
| 7 | #include <time.h> | ||
| 8 | #endif | ||
| 9 | |||
| 10 | #include "common/steady_clock.h" | ||
| 11 | |||
| 12 | namespace Common { | ||
| 13 | |||
| 14 | #ifdef _WIN32 | ||
| 15 | static s64 WindowsQueryPerformanceFrequency() { | ||
| 16 | LARGE_INTEGER frequency; | ||
| 17 | QueryPerformanceFrequency(&frequency); | ||
| 18 | return frequency.QuadPart; | ||
| 19 | } | ||
| 20 | |||
| 21 | static s64 WindowsQueryPerformanceCounter() { | ||
| 22 | LARGE_INTEGER counter; | ||
| 23 | QueryPerformanceCounter(&counter); | ||
| 24 | return counter.QuadPart; | ||
| 25 | } | ||
| 26 | #endif | ||
| 27 | |||
| 28 | SteadyClock::time_point SteadyClock::Now() noexcept { | ||
| 29 | #if defined(_WIN32) | ||
| 30 | static const auto freq = WindowsQueryPerformanceFrequency(); | ||
| 31 | const auto counter = WindowsQueryPerformanceCounter(); | ||
| 32 | |||
| 33 | // 10 MHz is a very common QPC frequency on modern PCs. | ||
| 34 | // Optimizing for this specific frequency can double the performance of | ||
| 35 | // this function by avoiding the expensive frequency conversion path. | ||
| 36 | static constexpr s64 TenMHz = 10'000'000; | ||
| 37 | |||
| 38 | if (freq == TenMHz) [[likely]] { | ||
| 39 | static_assert(period::den % TenMHz == 0); | ||
| 40 | static constexpr s64 Multiplier = period::den / TenMHz; | ||
| 41 | return time_point{duration{counter * Multiplier}}; | ||
| 42 | } | ||
| 43 | |||
| 44 | const auto whole = (counter / freq) * period::den; | ||
| 45 | const auto part = (counter % freq) * period::den / freq; | ||
| 46 | return time_point{duration{whole + part}}; | ||
| 47 | #elif defined(__APPLE__) | ||
| 48 | return time_point{duration{clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)}}; | ||
| 49 | #else | ||
| 50 | timespec ts; | ||
| 51 | clock_gettime(CLOCK_MONOTONIC, &ts); | ||
| 52 | return time_point{std::chrono::seconds{ts.tv_sec} + std::chrono::nanoseconds{ts.tv_nsec}}; | ||
| 53 | #endif | ||
| 54 | } | ||
| 55 | |||
| 56 | }; // namespace Common | ||
diff --git a/src/common/steady_clock.h b/src/common/steady_clock.h new file mode 100644 index 000000000..9497cf865 --- /dev/null +++ b/src/common/steady_clock.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <chrono> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | |||
| 10 | namespace Common { | ||
| 11 | |||
| 12 | struct SteadyClock { | ||
| 13 | using rep = s64; | ||
| 14 | using period = std::nano; | ||
| 15 | using duration = std::chrono::nanoseconds; | ||
| 16 | using time_point = std::chrono::time_point<SteadyClock>; | ||
| 17 | |||
| 18 | static constexpr bool is_steady = true; | ||
| 19 | |||
| 20 | [[nodiscard]] static time_point Now() noexcept; | ||
| 21 | }; | ||
| 22 | |||
| 23 | } // namespace Common | ||
diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp index ae07f2811..817e71d52 100644 --- a/src/common/wall_clock.cpp +++ b/src/common/wall_clock.cpp | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "common/steady_clock.h" | ||
| 4 | #include "common/uint128.h" | 5 | #include "common/uint128.h" |
| 5 | #include "common/wall_clock.h" | 6 | #include "common/wall_clock.h" |
| 6 | 7 | ||
| @@ -11,45 +12,32 @@ | |||
| 11 | 12 | ||
| 12 | namespace Common { | 13 | namespace Common { |
| 13 | 14 | ||
| 14 | using base_timer = std::chrono::steady_clock; | ||
| 15 | using base_time_point = std::chrono::time_point<base_timer>; | ||
| 16 | |||
| 17 | class StandardWallClock final : public WallClock { | 15 | class StandardWallClock final : public WallClock { |
| 18 | public: | 16 | public: |
| 19 | explicit StandardWallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_) | 17 | explicit StandardWallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_) |
| 20 | : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, false) { | 18 | : WallClock{emulated_cpu_frequency_, emulated_clock_frequency_, false}, |
| 21 | start_time = base_timer::now(); | 19 | start_time{SteadyClock::Now()} {} |
| 22 | } | ||
| 23 | 20 | ||
| 24 | std::chrono::nanoseconds GetTimeNS() override { | 21 | std::chrono::nanoseconds GetTimeNS() override { |
| 25 | base_time_point current = base_timer::now(); | 22 | return SteadyClock::Now() - start_time; |
| 26 | auto elapsed = current - start_time; | ||
| 27 | return std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed); | ||
| 28 | } | 23 | } |
| 29 | 24 | ||
| 30 | std::chrono::microseconds GetTimeUS() override { | 25 | std::chrono::microseconds GetTimeUS() override { |
| 31 | base_time_point current = base_timer::now(); | 26 | return std::chrono::duration_cast<std::chrono::microseconds>(GetTimeNS()); |
| 32 | auto elapsed = current - start_time; | ||
| 33 | return std::chrono::duration_cast<std::chrono::microseconds>(elapsed); | ||
| 34 | } | 27 | } |
| 35 | 28 | ||
| 36 | std::chrono::milliseconds GetTimeMS() override { | 29 | std::chrono::milliseconds GetTimeMS() override { |
| 37 | base_time_point current = base_timer::now(); | 30 | return std::chrono::duration_cast<std::chrono::milliseconds>(GetTimeNS()); |
| 38 | auto elapsed = current - start_time; | ||
| 39 | return std::chrono::duration_cast<std::chrono::milliseconds>(elapsed); | ||
| 40 | } | 31 | } |
| 41 | 32 | ||
| 42 | u64 GetClockCycles() override { | 33 | u64 GetClockCycles() override { |
| 43 | std::chrono::nanoseconds time_now = GetTimeNS(); | 34 | const u128 temp = Common::Multiply64Into128(GetTimeNS().count(), emulated_clock_frequency); |
| 44 | const u128 temporary = | 35 | return Common::Divide128On32(temp, NS_RATIO).first; |
| 45 | Common::Multiply64Into128(time_now.count(), emulated_clock_frequency); | ||
| 46 | return Common::Divide128On32(temporary, 1000000000).first; | ||
| 47 | } | 36 | } |
| 48 | 37 | ||
| 49 | u64 GetCPUCycles() override { | 38 | u64 GetCPUCycles() override { |
| 50 | std::chrono::nanoseconds time_now = GetTimeNS(); | 39 | const u128 temp = Common::Multiply64Into128(GetTimeNS().count(), emulated_cpu_frequency); |
| 51 | const u128 temporary = Common::Multiply64Into128(time_now.count(), emulated_cpu_frequency); | 40 | return Common::Divide128On32(temp, NS_RATIO).first; |
| 52 | return Common::Divide128On32(temporary, 1000000000).first; | ||
| 53 | } | 41 | } |
| 54 | 42 | ||
| 55 | void Pause([[maybe_unused]] bool is_paused) override { | 43 | void Pause([[maybe_unused]] bool is_paused) override { |
| @@ -57,7 +45,7 @@ public: | |||
| 57 | } | 45 | } |
| 58 | 46 | ||
| 59 | private: | 47 | private: |
| 60 | base_time_point start_time; | 48 | SteadyClock::time_point start_time; |
| 61 | }; | 49 | }; |
| 62 | 50 | ||
| 63 | #ifdef ARCHITECTURE_x86_64 | 51 | #ifdef ARCHITECTURE_x86_64 |
| @@ -93,4 +81,9 @@ std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency, | |||
| 93 | 81 | ||
| 94 | #endif | 82 | #endif |
| 95 | 83 | ||
| 84 | std::unique_ptr<WallClock> CreateStandardWallClock(u64 emulated_cpu_frequency, | ||
| 85 | u64 emulated_clock_frequency) { | ||
| 86 | return std::make_unique<StandardWallClock>(emulated_cpu_frequency, emulated_clock_frequency); | ||
| 87 | } | ||
| 88 | |||
| 96 | } // namespace Common | 89 | } // namespace Common |
diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h index 828a523a8..157ec5eae 100644 --- a/src/common/wall_clock.h +++ b/src/common/wall_clock.h | |||
| @@ -55,4 +55,7 @@ private: | |||
| 55 | [[nodiscard]] std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency, | 55 | [[nodiscard]] std::unique_ptr<WallClock> CreateBestMatchingClock(u64 emulated_cpu_frequency, |
| 56 | u64 emulated_clock_frequency); | 56 | u64 emulated_clock_frequency); |
| 57 | 57 | ||
| 58 | [[nodiscard]] std::unique_ptr<WallClock> CreateStandardWallClock(u64 emulated_cpu_frequency, | ||
| 59 | u64 emulated_clock_frequency); | ||
| 60 | |||
| 58 | } // namespace Common | 61 | } // namespace Common |
diff --git a/src/common/windows/timer_resolution.cpp b/src/common/windows/timer_resolution.cpp new file mode 100644 index 000000000..29c6e5c7e --- /dev/null +++ b/src/common/windows/timer_resolution.cpp | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <windows.h> | ||
| 5 | |||
| 6 | #include "common/windows/timer_resolution.h" | ||
| 7 | |||
| 8 | extern "C" { | ||
| 9 | // http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FTime%2FNtQueryTimerResolution.html | ||
| 10 | NTSYSAPI LONG NTAPI NtQueryTimerResolution(PULONG MinimumResolution, PULONG MaximumResolution, | ||
| 11 | PULONG CurrentResolution); | ||
| 12 | |||
| 13 | // http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FTime%2FNtSetTimerResolution.html | ||
| 14 | NTSYSAPI LONG NTAPI NtSetTimerResolution(ULONG DesiredResolution, BOOLEAN SetResolution, | ||
| 15 | PULONG CurrentResolution); | ||
| 16 | |||
| 17 | // http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FThread%2FNtDelayExecution.html | ||
| 18 | NTSYSAPI LONG NTAPI NtDelayExecution(BOOLEAN Alertable, PLARGE_INTEGER DelayInterval); | ||
| 19 | } | ||
| 20 | |||
| 21 | // Defines for compatibility with older Windows 10 SDKs. | ||
| 22 | |||
| 23 | #ifndef PROCESS_POWER_THROTTLING_EXECUTION_SPEED | ||
| 24 | #define PROCESS_POWER_THROTTLING_EXECUTION_SPEED 0x1 | ||
| 25 | #endif | ||
| 26 | #ifndef PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION | ||
| 27 | #define PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION 0x4 | ||
| 28 | #endif | ||
| 29 | |||
| 30 | namespace Common::Windows { | ||
| 31 | |||
| 32 | namespace { | ||
| 33 | |||
| 34 | using namespace std::chrono; | ||
| 35 | |||
| 36 | constexpr nanoseconds ToNS(ULONG hundred_ns) { | ||
| 37 | return nanoseconds{hundred_ns * 100}; | ||
| 38 | } | ||
| 39 | |||
| 40 | constexpr ULONG ToHundredNS(nanoseconds ns) { | ||
| 41 | return static_cast<ULONG>(ns.count()) / 100; | ||
| 42 | } | ||
| 43 | |||
| 44 | struct TimerResolution { | ||
| 45 | std::chrono::nanoseconds minimum; | ||
| 46 | std::chrono::nanoseconds maximum; | ||
| 47 | std::chrono::nanoseconds current; | ||
| 48 | }; | ||
| 49 | |||
| 50 | TimerResolution GetTimerResolution() { | ||
| 51 | ULONG MinimumTimerResolution; | ||
| 52 | ULONG MaximumTimerResolution; | ||
| 53 | ULONG CurrentTimerResolution; | ||
| 54 | NtQueryTimerResolution(&MinimumTimerResolution, &MaximumTimerResolution, | ||
| 55 | &CurrentTimerResolution); | ||
| 56 | return { | ||
| 57 | .minimum{ToNS(MinimumTimerResolution)}, | ||
| 58 | .maximum{ToNS(MaximumTimerResolution)}, | ||
| 59 | .current{ToNS(CurrentTimerResolution)}, | ||
| 60 | }; | ||
| 61 | } | ||
| 62 | |||
| 63 | void SetHighQoS() { | ||
| 64 | // https://learn.microsoft.com/en-us/windows/win32/procthread/quality-of-service | ||
| 65 | PROCESS_POWER_THROTTLING_STATE PowerThrottling{ | ||
| 66 | .Version{PROCESS_POWER_THROTTLING_CURRENT_VERSION}, | ||
| 67 | .ControlMask{PROCESS_POWER_THROTTLING_EXECUTION_SPEED | | ||
| 68 | PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION}, | ||
| 69 | .StateMask{}, | ||
| 70 | }; | ||
| 71 | SetProcessInformation(GetCurrentProcess(), ProcessPowerThrottling, &PowerThrottling, | ||
| 72 | sizeof(PROCESS_POWER_THROTTLING_STATE)); | ||
| 73 | } | ||
| 74 | |||
| 75 | } // Anonymous namespace | ||
| 76 | |||
| 77 | nanoseconds GetMinimumTimerResolution() { | ||
| 78 | return GetTimerResolution().minimum; | ||
| 79 | } | ||
| 80 | |||
| 81 | nanoseconds GetMaximumTimerResolution() { | ||
| 82 | return GetTimerResolution().maximum; | ||
| 83 | } | ||
| 84 | |||
| 85 | nanoseconds GetCurrentTimerResolution() { | ||
| 86 | return GetTimerResolution().current; | ||
| 87 | } | ||
| 88 | |||
| 89 | nanoseconds SetCurrentTimerResolution(nanoseconds timer_resolution) { | ||
| 90 | // Set the timer resolution, and return the current timer resolution. | ||
| 91 | const auto DesiredTimerResolution = ToHundredNS(timer_resolution); | ||
| 92 | ULONG CurrentTimerResolution; | ||
| 93 | NtSetTimerResolution(DesiredTimerResolution, TRUE, &CurrentTimerResolution); | ||
| 94 | return ToNS(CurrentTimerResolution); | ||
| 95 | } | ||
| 96 | |||
| 97 | nanoseconds SetCurrentTimerResolutionToMaximum() { | ||
| 98 | SetHighQoS(); | ||
| 99 | return SetCurrentTimerResolution(GetMaximumTimerResolution()); | ||
| 100 | } | ||
| 101 | |||
| 102 | void SleepForOneTick() { | ||
| 103 | LARGE_INTEGER DelayInterval{ | ||
| 104 | .QuadPart{-1}, | ||
| 105 | }; | ||
| 106 | NtDelayExecution(FALSE, &DelayInterval); | ||
| 107 | } | ||
| 108 | |||
| 109 | } // namespace Common::Windows | ||
diff --git a/src/common/windows/timer_resolution.h b/src/common/windows/timer_resolution.h new file mode 100644 index 000000000..e1e50a62d --- /dev/null +++ b/src/common/windows/timer_resolution.h | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <chrono> | ||
| 7 | |||
| 8 | namespace Common::Windows { | ||
| 9 | |||
| 10 | /// Returns the minimum (least precise) supported timer resolution in nanoseconds. | ||
| 11 | std::chrono::nanoseconds GetMinimumTimerResolution(); | ||
| 12 | |||
| 13 | /// Returns the maximum (most precise) supported timer resolution in nanoseconds. | ||
| 14 | std::chrono::nanoseconds GetMaximumTimerResolution(); | ||
| 15 | |||
| 16 | /// Returns the current timer resolution in nanoseconds. | ||
| 17 | std::chrono::nanoseconds GetCurrentTimerResolution(); | ||
| 18 | |||
| 19 | /** | ||
| 20 | * Sets the current timer resolution. | ||
| 21 | * | ||
| 22 | * @param timer_resolution Timer resolution in nanoseconds. | ||
| 23 | * | ||
| 24 | * @returns The current timer resolution. | ||
| 25 | */ | ||
| 26 | std::chrono::nanoseconds SetCurrentTimerResolution(std::chrono::nanoseconds timer_resolution); | ||
| 27 | |||
| 28 | /** | ||
| 29 | * Sets the current timer resolution to the maximum supported timer resolution. | ||
| 30 | * | ||
| 31 | * @returns The current timer resolution. | ||
| 32 | */ | ||
| 33 | std::chrono::nanoseconds SetCurrentTimerResolutionToMaximum(); | ||
| 34 | |||
| 35 | /// Sleep for one tick of the current timer resolution. | ||
| 36 | void SleepForOneTick(); | ||
| 37 | |||
| 38 | } // namespace Common::Windows | ||
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 8b08332ab..bc1a973b0 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <thread> | 6 | #include <thread> |
| 7 | 7 | ||
| 8 | #include "common/atomic_ops.h" | 8 | #include "common/atomic_ops.h" |
| 9 | #include "common/steady_clock.h" | ||
| 9 | #include "common/uint128.h" | 10 | #include "common/uint128.h" |
| 10 | #include "common/x64/native_clock.h" | 11 | #include "common/x64/native_clock.h" |
| 11 | 12 | ||
| @@ -39,6 +40,12 @@ static u64 FencedRDTSC() { | |||
| 39 | } | 40 | } |
| 40 | #endif | 41 | #endif |
| 41 | 42 | ||
| 43 | template <u64 Nearest> | ||
| 44 | static u64 RoundToNearest(u64 value) { | ||
| 45 | const auto mod = value % Nearest; | ||
| 46 | return mod >= (Nearest / 2) ? (value - mod + Nearest) : (value - mod); | ||
| 47 | } | ||
| 48 | |||
| 42 | u64 EstimateRDTSCFrequency() { | 49 | u64 EstimateRDTSCFrequency() { |
| 43 | // Discard the first result measuring the rdtsc. | 50 | // Discard the first result measuring the rdtsc. |
| 44 | FencedRDTSC(); | 51 | FencedRDTSC(); |
| @@ -46,18 +53,18 @@ u64 EstimateRDTSCFrequency() { | |||
| 46 | FencedRDTSC(); | 53 | FencedRDTSC(); |
| 47 | 54 | ||
| 48 | // Get the current time. | 55 | // Get the current time. |
| 49 | const auto start_time = std::chrono::steady_clock::now(); | 56 | const auto start_time = Common::SteadyClock::Now(); |
| 50 | const u64 tsc_start = FencedRDTSC(); | 57 | const u64 tsc_start = FencedRDTSC(); |
| 51 | // Wait for 200 milliseconds. | 58 | // Wait for 250 milliseconds. |
| 52 | std::this_thread::sleep_for(std::chrono::milliseconds{200}); | 59 | std::this_thread::sleep_for(std::chrono::milliseconds{250}); |
| 53 | const auto end_time = std::chrono::steady_clock::now(); | 60 | const auto end_time = Common::SteadyClock::Now(); |
| 54 | const u64 tsc_end = FencedRDTSC(); | 61 | const u64 tsc_end = FencedRDTSC(); |
| 55 | // Calculate differences. | 62 | // Calculate differences. |
| 56 | const u64 timer_diff = static_cast<u64>( | 63 | const u64 timer_diff = static_cast<u64>( |
| 57 | std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count()); | 64 | std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count()); |
| 58 | const u64 tsc_diff = tsc_end - tsc_start; | 65 | const u64 tsc_diff = tsc_end - tsc_start; |
| 59 | const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff); | 66 | const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, timer_diff); |
| 60 | return tsc_freq; | 67 | return RoundToNearest<1000>(tsc_freq); |
| 61 | } | 68 | } |
| 62 | 69 | ||
| 63 | namespace X64 { | 70 | namespace X64 { |
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 3a63b52e3..742cfb996 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | #include <string> | 6 | #include <string> |
| 7 | #include <tuple> | 7 | #include <tuple> |
| 8 | 8 | ||
| 9 | #ifdef _WIN32 | ||
| 10 | #include "common/windows/timer_resolution.h" | ||
| 11 | #endif | ||
| 12 | |||
| 9 | #include "common/microprofile.h" | 13 | #include "common/microprofile.h" |
| 10 | #include "core/core_timing.h" | 14 | #include "core/core_timing.h" |
| 11 | #include "core/core_timing_util.h" | 15 | #include "core/core_timing_util.h" |
| @@ -38,7 +42,8 @@ struct CoreTiming::Event { | |||
| 38 | }; | 42 | }; |
| 39 | 43 | ||
| 40 | CoreTiming::CoreTiming() | 44 | CoreTiming::CoreTiming() |
| 41 | : clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {} | 45 | : cpu_clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)}, |
| 46 | event_clock{Common::CreateStandardWallClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {} | ||
| 42 | 47 | ||
| 43 | CoreTiming::~CoreTiming() { | 48 | CoreTiming::~CoreTiming() { |
| 44 | Reset(); | 49 | Reset(); |
| @@ -185,15 +190,15 @@ void CoreTiming::ResetTicks() { | |||
| 185 | } | 190 | } |
| 186 | 191 | ||
| 187 | u64 CoreTiming::GetCPUTicks() const { | 192 | u64 CoreTiming::GetCPUTicks() const { |
| 188 | if (is_multicore) { | 193 | if (is_multicore) [[likely]] { |
| 189 | return clock->GetCPUCycles(); | 194 | return cpu_clock->GetCPUCycles(); |
| 190 | } | 195 | } |
| 191 | return ticks; | 196 | return ticks; |
| 192 | } | 197 | } |
| 193 | 198 | ||
| 194 | u64 CoreTiming::GetClockTicks() const { | 199 | u64 CoreTiming::GetClockTicks() const { |
| 195 | if (is_multicore) { | 200 | if (is_multicore) [[likely]] { |
| 196 | return clock->GetClockCycles(); | 201 | return cpu_clock->GetClockCycles(); |
| 197 | } | 202 | } |
| 198 | return CpuCyclesToClockCycles(ticks); | 203 | return CpuCyclesToClockCycles(ticks); |
| 199 | } | 204 | } |
| @@ -252,21 +257,20 @@ void CoreTiming::ThreadLoop() { | |||
| 252 | const auto next_time = Advance(); | 257 | const auto next_time = Advance(); |
| 253 | if (next_time) { | 258 | if (next_time) { |
| 254 | // There are more events left in the queue, wait until the next event. | 259 | // There are more events left in the queue, wait until the next event. |
| 255 | const auto wait_time = *next_time - GetGlobalTimeNs().count(); | 260 | auto wait_time = *next_time - GetGlobalTimeNs().count(); |
| 256 | if (wait_time > 0) { | 261 | if (wait_time > 0) { |
| 257 | #ifdef _WIN32 | 262 | #ifdef _WIN32 |
| 258 | // Assume a timer resolution of 1ms. | 263 | const auto timer_resolution_ns = |
| 259 | static constexpr s64 TimerResolutionNS = 1000000; | 264 | Common::Windows::GetCurrentTimerResolution().count(); |
| 260 | 265 | ||
| 261 | // Sleep in discrete intervals of the timer resolution, and spin the rest. | 266 | while (!paused && !event.IsSet() && wait_time > 0) { |
| 262 | const auto sleep_time = wait_time - (wait_time % TimerResolutionNS); | 267 | wait_time = *next_time - GetGlobalTimeNs().count(); |
| 263 | if (sleep_time > 0) { | ||
| 264 | event.WaitFor(std::chrono::nanoseconds(sleep_time)); | ||
| 265 | } | ||
| 266 | 268 | ||
| 267 | while (!paused && !event.IsSet() && GetGlobalTimeNs().count() < *next_time) { | 269 | if (wait_time >= timer_resolution_ns) { |
| 268 | // Yield to reduce thread starvation. | 270 | Common::Windows::SleepForOneTick(); |
| 269 | std::this_thread::yield(); | 271 | } else { |
| 272 | std::this_thread::yield(); | ||
| 273 | } | ||
| 270 | } | 274 | } |
| 271 | 275 | ||
| 272 | if (event.IsSet()) { | 276 | if (event.IsSet()) { |
| @@ -285,9 +289,9 @@ void CoreTiming::ThreadLoop() { | |||
| 285 | } | 289 | } |
| 286 | 290 | ||
| 287 | paused_set = true; | 291 | paused_set = true; |
| 288 | clock->Pause(true); | 292 | event_clock->Pause(true); |
| 289 | pause_event.Wait(); | 293 | pause_event.Wait(); |
| 290 | clock->Pause(false); | 294 | event_clock->Pause(false); |
| 291 | } | 295 | } |
| 292 | } | 296 | } |
| 293 | 297 | ||
| @@ -303,16 +307,23 @@ void CoreTiming::Reset() { | |||
| 303 | has_started = false; | 307 | has_started = false; |
| 304 | } | 308 | } |
| 305 | 309 | ||
| 310 | std::chrono::nanoseconds CoreTiming::GetCPUTimeNs() const { | ||
| 311 | if (is_multicore) [[likely]] { | ||
| 312 | return cpu_clock->GetTimeNS(); | ||
| 313 | } | ||
| 314 | return CyclesToNs(ticks); | ||
| 315 | } | ||
| 316 | |||
| 306 | std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { | 317 | std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { |
| 307 | if (is_multicore) { | 318 | if (is_multicore) [[likely]] { |
| 308 | return clock->GetTimeNS(); | 319 | return event_clock->GetTimeNS(); |
| 309 | } | 320 | } |
| 310 | return CyclesToNs(ticks); | 321 | return CyclesToNs(ticks); |
| 311 | } | 322 | } |
| 312 | 323 | ||
| 313 | std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { | 324 | std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { |
| 314 | if (is_multicore) { | 325 | if (is_multicore) [[likely]] { |
| 315 | return clock->GetTimeUS(); | 326 | return event_clock->GetTimeUS(); |
| 316 | } | 327 | } |
| 317 | return CyclesToUs(ticks); | 328 | return CyclesToUs(ticks); |
| 318 | } | 329 | } |
diff --git a/src/core/core_timing.h b/src/core/core_timing.h index da366637b..4b89c0c39 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h | |||
| @@ -122,6 +122,9 @@ public: | |||
| 122 | /// Returns current time in emulated in Clock cycles | 122 | /// Returns current time in emulated in Clock cycles |
| 123 | u64 GetClockTicks() const; | 123 | u64 GetClockTicks() const; |
| 124 | 124 | ||
| 125 | /// Returns current time in nanoseconds. | ||
| 126 | std::chrono::nanoseconds GetCPUTimeNs() const; | ||
| 127 | |||
| 125 | /// Returns current time in microseconds. | 128 | /// Returns current time in microseconds. |
| 126 | std::chrono::microseconds GetGlobalTimeUs() const; | 129 | std::chrono::microseconds GetGlobalTimeUs() const; |
| 127 | 130 | ||
| @@ -139,7 +142,8 @@ private: | |||
| 139 | 142 | ||
| 140 | void Reset(); | 143 | void Reset(); |
| 141 | 144 | ||
| 142 | std::unique_ptr<Common::WallClock> clock; | 145 | std::unique_ptr<Common::WallClock> cpu_clock; |
| 146 | std::unique_ptr<Common::WallClock> event_clock; | ||
| 143 | 147 | ||
| 144 | s64 global_timer = 0; | 148 | s64 global_timer = 0; |
| 145 | 149 | ||
diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h index 45567b840..191c28bb4 100644 --- a/src/core/hardware_properties.h +++ b/src/core/hardware_properties.h | |||
| @@ -13,11 +13,9 @@ namespace Core { | |||
| 13 | 13 | ||
| 14 | namespace Hardware { | 14 | namespace Hardware { |
| 15 | 15 | ||
| 16 | // The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz | 16 | constexpr u64 BASE_CLOCK_RATE = 1'020'000'000; // Default CPU Frequency = 1020 MHz |
| 17 | // The exact value used is of course unverified. | 17 | constexpr u64 CNTFREQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz |
| 18 | constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch cpu frequency is 1020MHz un/docked | 18 | constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores |
| 19 | constexpr u64 CNTFREQ = 19200000; // Switch's hardware clock speed | ||
| 20 | constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores | ||
| 21 | 19 | ||
| 22 | // Virtual to Physical core map. | 20 | // Virtual to Physical core map. |
| 23 | constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{ | 21 | constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{ |
diff --git a/src/core/hle/kernel/k_address_space_info.cpp b/src/core/hle/kernel/k_address_space_info.cpp index 97972ebae..c36eb5dc4 100644 --- a/src/core/hle/kernel/k_address_space_info.cpp +++ b/src/core/hle/kernel/k_address_space_info.cpp | |||
| @@ -44,11 +44,11 @@ const KAddressSpaceInfo& GetAddressSpaceInfo(size_t width, KAddressSpaceInfo::Ty | |||
| 44 | 44 | ||
| 45 | } // namespace | 45 | } // namespace |
| 46 | 46 | ||
| 47 | uintptr_t KAddressSpaceInfo::GetAddressSpaceStart(size_t width, KAddressSpaceInfo::Type type) { | 47 | std::size_t KAddressSpaceInfo::GetAddressSpaceStart(size_t width, KAddressSpaceInfo::Type type) { |
| 48 | return GetAddressSpaceInfo(width, type).address; | 48 | return GetAddressSpaceInfo(width, type).address; |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | size_t KAddressSpaceInfo::GetAddressSpaceSize(size_t width, KAddressSpaceInfo::Type type) { | 51 | std::size_t KAddressSpaceInfo::GetAddressSpaceSize(size_t width, KAddressSpaceInfo::Type type) { |
| 52 | return GetAddressSpaceInfo(width, type).size; | 52 | return GetAddressSpaceInfo(width, type).size; |
| 53 | } | 53 | } |
| 54 | 54 | ||
diff --git a/src/core/hle/kernel/k_address_space_info.h b/src/core/hle/kernel/k_address_space_info.h index 69e9d77f2..9a26f6b90 100644 --- a/src/core/hle/kernel/k_address_space_info.h +++ b/src/core/hle/kernel/k_address_space_info.h | |||
| @@ -18,7 +18,7 @@ struct KAddressSpaceInfo final { | |||
| 18 | Count, | 18 | Count, |
| 19 | }; | 19 | }; |
| 20 | 20 | ||
| 21 | static u64 GetAddressSpaceStart(std::size_t width, Type type); | 21 | static std::size_t GetAddressSpaceStart(std::size_t width, Type type); |
| 22 | static std::size_t GetAddressSpaceSize(std::size_t width, Type type); | 22 | static std::size_t GetAddressSpaceSize(std::size_t width, Type type); |
| 23 | 23 | ||
| 24 | const std::size_t bit_width{}; | 24 | const std::size_t bit_width{}; |
diff --git a/src/core/hle/kernel/k_device_address_space.h b/src/core/hle/kernel/k_device_address_space.h index 4709df995..b4a014c38 100644 --- a/src/core/hle/kernel/k_device_address_space.h +++ b/src/core/hle/kernel/k_device_address_space.h | |||
| @@ -21,9 +21,9 @@ public: | |||
| 21 | ~KDeviceAddressSpace(); | 21 | ~KDeviceAddressSpace(); |
| 22 | 22 | ||
| 23 | Result Initialize(u64 address, u64 size); | 23 | Result Initialize(u64 address, u64 size); |
| 24 | void Finalize(); | 24 | void Finalize() override; |
| 25 | 25 | ||
| 26 | bool IsInitialized() const { | 26 | bool IsInitialized() const override { |
| 27 | return m_is_initialized; | 27 | return m_is_initialized; |
| 28 | } | 28 | } |
| 29 | static void PostDestroy(uintptr_t arg) {} | 29 | static void PostDestroy(uintptr_t arg) {} |
diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp index b9d22b414..626517619 100644 --- a/src/core/hle/kernel/k_resource_limit.cpp +++ b/src/core/hle/kernel/k_resource_limit.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "common/assert.h" | 4 | #include "common/assert.h" |
| 5 | #include "common/overflow.h" | ||
| 5 | #include "core/core.h" | 6 | #include "core/core.h" |
| 6 | #include "core/core_timing.h" | 7 | #include "core/core_timing.h" |
| 7 | #include "core/hle/kernel/k_resource_limit.h" | 8 | #include "core/hle/kernel/k_resource_limit.h" |
| @@ -104,7 +105,7 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) { | |||
| 104 | ASSERT(current_hints[index] <= current_values[index]); | 105 | ASSERT(current_hints[index] <= current_values[index]); |
| 105 | 106 | ||
| 106 | // If we would overflow, don't allow to succeed. | 107 | // If we would overflow, don't allow to succeed. |
| 107 | if (current_values[index] + value <= current_values[index]) { | 108 | if (Common::WrappingAdd(current_values[index], value) <= current_values[index]) { |
| 108 | break; | 109 | break; |
| 109 | } | 110 | } |
| 110 | 111 | ||
diff --git a/src/core/hle/kernel/svc/svc_synchronization.cpp b/src/core/hle/kernel/svc/svc_synchronization.cpp index 1a8f7e191..9e7bf9530 100644 --- a/src/core/hle/kernel/svc/svc_synchronization.cpp +++ b/src/core/hle/kernel/svc/svc_synchronization.cpp | |||
| @@ -48,19 +48,15 @@ Result ResetSignal(Core::System& system, Handle handle) { | |||
| 48 | return ResultInvalidHandle; | 48 | return ResultInvalidHandle; |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | 51 | static Result WaitSynchronization(Core::System& system, int32_t* out_index, const Handle* handles, |
| 52 | Result WaitSynchronization(Core::System& system, s32* index, VAddr handles_address, s32 num_handles, | 52 | int32_t num_handles, int64_t timeout_ns) { |
| 53 | s64 nano_seconds) { | ||
| 54 | LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, num_handles={}, nano_seconds={}", | ||
| 55 | handles_address, num_handles, nano_seconds); | ||
| 56 | |||
| 57 | // Ensure number of handles is valid. | 53 | // Ensure number of handles is valid. |
| 58 | R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange); | 54 | R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange); |
| 59 | 55 | ||
| 56 | // Get the synchronization context. | ||
| 60 | auto& kernel = system.Kernel(); | 57 | auto& kernel = system.Kernel(); |
| 58 | auto& handle_table = GetCurrentProcess(kernel).GetHandleTable(); | ||
| 61 | std::vector<KSynchronizationObject*> objs(num_handles); | 59 | std::vector<KSynchronizationObject*> objs(num_handles); |
| 62 | const auto& handle_table = GetCurrentProcess(kernel).GetHandleTable(); | ||
| 63 | Handle* handles = system.Memory().GetPointer<Handle>(handles_address); | ||
| 64 | 60 | ||
| 65 | // Copy user handles. | 61 | // Copy user handles. |
| 66 | if (num_handles > 0) { | 62 | if (num_handles > 0) { |
| @@ -68,21 +64,38 @@ Result WaitSynchronization(Core::System& system, s32* index, VAddr handles_addre | |||
| 68 | R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles, | 64 | R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles, |
| 69 | num_handles), | 65 | num_handles), |
| 70 | ResultInvalidHandle); | 66 | ResultInvalidHandle); |
| 71 | for (const auto& obj : objs) { | ||
| 72 | kernel.RegisterInUseObject(obj); | ||
| 73 | } | ||
| 74 | } | 67 | } |
| 75 | 68 | ||
| 76 | // Ensure handles are closed when we're done. | 69 | // Ensure handles are closed when we're done. |
| 77 | SCOPE_EXIT({ | 70 | SCOPE_EXIT({ |
| 78 | for (s32 i = 0; i < num_handles; ++i) { | 71 | for (auto i = 0; i < num_handles; ++i) { |
| 79 | kernel.UnregisterInUseObject(objs[i]); | ||
| 80 | objs[i]->Close(); | 72 | objs[i]->Close(); |
| 81 | } | 73 | } |
| 82 | }); | 74 | }); |
| 83 | 75 | ||
| 84 | return KSynchronizationObject::Wait(kernel, index, objs.data(), static_cast<s32>(objs.size()), | 76 | // Wait on the objects. |
| 85 | nano_seconds); | 77 | Result res = KSynchronizationObject::Wait(kernel, out_index, objs.data(), |
| 78 | static_cast<s32>(objs.size()), timeout_ns); | ||
| 79 | |||
| 80 | R_SUCCEED_IF(res == ResultSessionClosed); | ||
| 81 | R_RETURN(res); | ||
| 82 | } | ||
| 83 | |||
| 84 | /// Wait for the given handles to synchronize, timeout after the specified nanoseconds | ||
| 85 | Result WaitSynchronization(Core::System& system, int32_t* out_index, VAddr user_handles, | ||
| 86 | int32_t num_handles, int64_t timeout_ns) { | ||
| 87 | LOG_TRACE(Kernel_SVC, "called user_handles={:#x}, num_handles={}, timeout_ns={}", user_handles, | ||
| 88 | num_handles, timeout_ns); | ||
| 89 | |||
| 90 | // Ensure number of handles is valid. | ||
| 91 | R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange); | ||
| 92 | |||
| 93 | std::vector<Handle> handles(num_handles); | ||
| 94 | if (num_handles > 0) { | ||
| 95 | system.Memory().ReadBlock(user_handles, handles.data(), num_handles * sizeof(Handle)); | ||
| 96 | } | ||
| 97 | |||
| 98 | R_RETURN(WaitSynchronization(system, out_index, handles.data(), num_handles, timeout_ns)); | ||
| 86 | } | 99 | } |
| 87 | 100 | ||
| 88 | /// Resumes a thread waiting on WaitSynchronization | 101 | /// Resumes a thread waiting on WaitSynchronization |
diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index b4cd39a20..8b57ebe07 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp | |||
| @@ -307,8 +307,8 @@ Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identif | |||
| 307 | switch (polling_mode) { | 307 | switch (polling_mode) { |
| 308 | case Common::Input::PollingMode::Active: | 308 | case Common::Input::PollingMode::Active: |
| 309 | return static_cast<Common::Input::DriverResult>(handle->SetActiveMode()); | 309 | return static_cast<Common::Input::DriverResult>(handle->SetActiveMode()); |
| 310 | case Common::Input::PollingMode::Pasive: | 310 | case Common::Input::PollingMode::Passive: |
| 311 | return static_cast<Common::Input::DriverResult>(handle->SetPasiveMode()); | 311 | return static_cast<Common::Input::DriverResult>(handle->SetPassiveMode()); |
| 312 | case Common::Input::PollingMode::IR: | 312 | case Common::Input::PollingMode::IR: |
| 313 | return static_cast<Common::Input::DriverResult>(handle->SetIrMode()); | 313 | return static_cast<Common::Input::DriverResult>(handle->SetIrMode()); |
| 314 | case Common::Input::PollingMode::NFC: | 314 | case Common::Input::PollingMode::NFC: |
diff --git a/src/input_common/drivers/virtual_amiibo.h b/src/input_common/drivers/virtual_amiibo.h index 13cacfc0a..488d00b31 100644 --- a/src/input_common/drivers/virtual_amiibo.h +++ b/src/input_common/drivers/virtual_amiibo.h | |||
| @@ -60,6 +60,6 @@ private: | |||
| 60 | std::string file_path{}; | 60 | std::string file_path{}; |
| 61 | State state{State::Initialized}; | 61 | State state{State::Initialized}; |
| 62 | std::vector<u8> nfc_data; | 62 | std::vector<u8> nfc_data; |
| 63 | Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Pasive}; | 63 | Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Passive}; |
| 64 | }; | 64 | }; |
| 65 | } // namespace InputCommon | 65 | } // namespace InputCommon |
diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index e65b6b845..78cc5893c 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp | |||
| @@ -410,7 +410,7 @@ DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) { | |||
| 410 | return result; | 410 | return result; |
| 411 | } | 411 | } |
| 412 | 412 | ||
| 413 | DriverResult JoyconDriver::SetPasiveMode() { | 413 | DriverResult JoyconDriver::SetPassiveMode() { |
| 414 | std::scoped_lock lock{mutex}; | 414 | std::scoped_lock lock{mutex}; |
| 415 | motion_enabled = false; | 415 | motion_enabled = false; |
| 416 | hidbus_enabled = false; | 416 | hidbus_enabled = false; |
diff --git a/src/input_common/helpers/joycon_driver.h b/src/input_common/helpers/joycon_driver.h index c1e189fa5..b52a13ecf 100644 --- a/src/input_common/helpers/joycon_driver.h +++ b/src/input_common/helpers/joycon_driver.h | |||
| @@ -44,7 +44,7 @@ public: | |||
| 44 | DriverResult SetVibration(const VibrationValue& vibration); | 44 | DriverResult SetVibration(const VibrationValue& vibration); |
| 45 | DriverResult SetLedConfig(u8 led_pattern); | 45 | DriverResult SetLedConfig(u8 led_pattern); |
| 46 | DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_); | 46 | DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_); |
| 47 | DriverResult SetPasiveMode(); | 47 | DriverResult SetPassiveMode(); |
| 48 | DriverResult SetActiveMode(); | 48 | DriverResult SetActiveMode(); |
| 49 | DriverResult SetIrMode(); | 49 | DriverResult SetIrMode(); |
| 50 | DriverResult SetNfcMode(); | 50 | DriverResult SetNfcMode(); |
diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h index 2e50a99a8..dcac0e422 100644 --- a/src/input_common/helpers/joycon_protocol/joycon_types.h +++ b/src/input_common/helpers/joycon_protocol/joycon_types.h | |||
| @@ -78,7 +78,7 @@ enum class PadButton : u32 { | |||
| 78 | Capture = 0x200000, | 78 | Capture = 0x200000, |
| 79 | }; | 79 | }; |
| 80 | 80 | ||
| 81 | enum class PasivePadButton : u32 { | 81 | enum class PassivePadButton : u32 { |
| 82 | Down_A = 0x0001, | 82 | Down_A = 0x0001, |
| 83 | Right_X = 0x0002, | 83 | Right_X = 0x0002, |
| 84 | Left_B = 0x0004, | 84 | Left_B = 0x0004, |
| @@ -95,7 +95,7 @@ enum class PasivePadButton : u32 { | |||
| 95 | ZL_ZR = 0x8000, | 95 | ZL_ZR = 0x8000, |
| 96 | }; | 96 | }; |
| 97 | 97 | ||
| 98 | enum class PasivePadStick : u8 { | 98 | enum class PassivePadStick : u8 { |
| 99 | Right = 0x00, | 99 | Right = 0x00, |
| 100 | RightDown = 0x01, | 100 | RightDown = 0x01, |
| 101 | Down = 0x02, | 101 | Down = 0x02, |
diff --git a/src/input_common/helpers/joycon_protocol/poller.cpp b/src/input_common/helpers/joycon_protocol/poller.cpp index ab48352b8..dca797f7a 100644 --- a/src/input_common/helpers/joycon_protocol/poller.cpp +++ b/src/input_common/helpers/joycon_protocol/poller.cpp | |||
| @@ -48,13 +48,13 @@ void JoyconPoller::ReadPassiveMode(std::span<u8> buffer) { | |||
| 48 | 48 | ||
| 49 | switch (device_type) { | 49 | switch (device_type) { |
| 50 | case ControllerType::Left: | 50 | case ControllerType::Left: |
| 51 | UpdatePasiveLeftPadInput(data); | 51 | UpdatePassiveLeftPadInput(data); |
| 52 | break; | 52 | break; |
| 53 | case ControllerType::Right: | 53 | case ControllerType::Right: |
| 54 | UpdatePasiveRightPadInput(data); | 54 | UpdatePassiveRightPadInput(data); |
| 55 | break; | 55 | break; |
| 56 | case ControllerType::Pro: | 56 | case ControllerType::Pro: |
| 57 | UpdatePasiveProPadInput(data); | 57 | UpdatePassiveProPadInput(data); |
| 58 | break; | 58 | break; |
| 59 | default: | 59 | default: |
| 60 | break; | 60 | break; |
| @@ -210,12 +210,12 @@ void JoyconPoller::UpdateActiveProPadInput(const InputReportActive& input, | |||
| 210 | } | 210 | } |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | void JoyconPoller::UpdatePasiveLeftPadInput(const InputReportPassive& input) { | 213 | void JoyconPoller::UpdatePassiveLeftPadInput(const InputReportPassive& input) { |
| 214 | static constexpr std::array<PasivePadButton, 11> left_buttons{ | 214 | static constexpr std::array<PassivePadButton, 11> left_buttons{ |
| 215 | PasivePadButton::Down_A, PasivePadButton::Right_X, PasivePadButton::Left_B, | 215 | PassivePadButton::Down_A, PassivePadButton::Right_X, PassivePadButton::Left_B, |
| 216 | PasivePadButton::Up_Y, PasivePadButton::SL, PasivePadButton::SR, | 216 | PassivePadButton::Up_Y, PassivePadButton::SL, PassivePadButton::SR, |
| 217 | PasivePadButton::L_R, PasivePadButton::ZL_ZR, PasivePadButton::Minus, | 217 | PassivePadButton::L_R, PassivePadButton::ZL_ZR, PassivePadButton::Minus, |
| 218 | PasivePadButton::Capture, PasivePadButton::StickL, | 218 | PassivePadButton::Capture, PassivePadButton::StickL, |
| 219 | }; | 219 | }; |
| 220 | 220 | ||
| 221 | for (auto left_button : left_buttons) { | 221 | for (auto left_button : left_buttons) { |
| @@ -225,17 +225,17 @@ void JoyconPoller::UpdatePasiveLeftPadInput(const InputReportPassive& input) { | |||
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | const auto [left_axis_x, left_axis_y] = | 227 | const auto [left_axis_x, left_axis_y] = |
| 228 | GetPassiveAxisValue(static_cast<PasivePadStick>(input.stick_state)); | 228 | GetPassiveAxisValue(static_cast<PassivePadStick>(input.stick_state)); |
| 229 | callbacks.on_stick_data(static_cast<int>(PadAxes::LeftStickX), left_axis_x); | 229 | callbacks.on_stick_data(static_cast<int>(PadAxes::LeftStickX), left_axis_x); |
| 230 | callbacks.on_stick_data(static_cast<int>(PadAxes::LeftStickY), left_axis_y); | 230 | callbacks.on_stick_data(static_cast<int>(PadAxes::LeftStickY), left_axis_y); |
| 231 | } | 231 | } |
| 232 | 232 | ||
| 233 | void JoyconPoller::UpdatePasiveRightPadInput(const InputReportPassive& input) { | 233 | void JoyconPoller::UpdatePassiveRightPadInput(const InputReportPassive& input) { |
| 234 | static constexpr std::array<PasivePadButton, 11> right_buttons{ | 234 | static constexpr std::array<PassivePadButton, 11> right_buttons{ |
| 235 | PasivePadButton::Down_A, PasivePadButton::Right_X, PasivePadButton::Left_B, | 235 | PassivePadButton::Down_A, PassivePadButton::Right_X, PassivePadButton::Left_B, |
| 236 | PasivePadButton::Up_Y, PasivePadButton::SL, PasivePadButton::SR, | 236 | PassivePadButton::Up_Y, PassivePadButton::SL, PassivePadButton::SR, |
| 237 | PasivePadButton::L_R, PasivePadButton::ZL_ZR, PasivePadButton::Plus, | 237 | PassivePadButton::L_R, PassivePadButton::ZL_ZR, PassivePadButton::Plus, |
| 238 | PasivePadButton::Home, PasivePadButton::StickR, | 238 | PassivePadButton::Home, PassivePadButton::StickR, |
| 239 | }; | 239 | }; |
| 240 | 240 | ||
| 241 | for (auto right_button : right_buttons) { | 241 | for (auto right_button : right_buttons) { |
| @@ -245,18 +245,18 @@ void JoyconPoller::UpdatePasiveRightPadInput(const InputReportPassive& input) { | |||
| 245 | } | 245 | } |
| 246 | 246 | ||
| 247 | const auto [right_axis_x, right_axis_y] = | 247 | const auto [right_axis_x, right_axis_y] = |
| 248 | GetPassiveAxisValue(static_cast<PasivePadStick>(input.stick_state)); | 248 | GetPassiveAxisValue(static_cast<PassivePadStick>(input.stick_state)); |
| 249 | callbacks.on_stick_data(static_cast<int>(PadAxes::RightStickX), right_axis_x); | 249 | callbacks.on_stick_data(static_cast<int>(PadAxes::RightStickX), right_axis_x); |
| 250 | callbacks.on_stick_data(static_cast<int>(PadAxes::RightStickY), right_axis_y); | 250 | callbacks.on_stick_data(static_cast<int>(PadAxes::RightStickY), right_axis_y); |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | void JoyconPoller::UpdatePasiveProPadInput(const InputReportPassive& input) { | 253 | void JoyconPoller::UpdatePassiveProPadInput(const InputReportPassive& input) { |
| 254 | static constexpr std::array<PasivePadButton, 14> pro_buttons{ | 254 | static constexpr std::array<PassivePadButton, 14> pro_buttons{ |
| 255 | PasivePadButton::Down_A, PasivePadButton::Right_X, PasivePadButton::Left_B, | 255 | PassivePadButton::Down_A, PassivePadButton::Right_X, PassivePadButton::Left_B, |
| 256 | PasivePadButton::Up_Y, PasivePadButton::SL, PasivePadButton::SR, | 256 | PassivePadButton::Up_Y, PassivePadButton::SL, PassivePadButton::SR, |
| 257 | PasivePadButton::L_R, PasivePadButton::ZL_ZR, PasivePadButton::Minus, | 257 | PassivePadButton::L_R, PassivePadButton::ZL_ZR, PassivePadButton::Minus, |
| 258 | PasivePadButton::Plus, PasivePadButton::Capture, PasivePadButton::Home, | 258 | PassivePadButton::Plus, PassivePadButton::Capture, PassivePadButton::Home, |
| 259 | PasivePadButton::StickL, PasivePadButton::StickR, | 259 | PassivePadButton::StickL, PassivePadButton::StickR, |
| 260 | }; | 260 | }; |
| 261 | 261 | ||
| 262 | for (auto pro_button : pro_buttons) { | 262 | for (auto pro_button : pro_buttons) { |
| @@ -266,9 +266,9 @@ void JoyconPoller::UpdatePasiveProPadInput(const InputReportPassive& input) { | |||
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | const auto [left_axis_x, left_axis_y] = | 268 | const auto [left_axis_x, left_axis_y] = |
| 269 | GetPassiveAxisValue(static_cast<PasivePadStick>(input.stick_state && 0xf)); | 269 | GetPassiveAxisValue(static_cast<PassivePadStick>(input.stick_state & 0xf)); |
| 270 | const auto [right_axis_x, right_axis_y] = | 270 | const auto [right_axis_x, right_axis_y] = |
| 271 | GetPassiveAxisValue(static_cast<PasivePadStick>(input.stick_state >> 4)); | 271 | GetPassiveAxisValue(static_cast<PassivePadStick>(input.stick_state >> 4)); |
| 272 | callbacks.on_stick_data(static_cast<int>(PadAxes::LeftStickX), left_axis_x); | 272 | callbacks.on_stick_data(static_cast<int>(PadAxes::LeftStickX), left_axis_x); |
| 273 | callbacks.on_stick_data(static_cast<int>(PadAxes::LeftStickY), left_axis_y); | 273 | callbacks.on_stick_data(static_cast<int>(PadAxes::LeftStickY), left_axis_y); |
| 274 | callbacks.on_stick_data(static_cast<int>(PadAxes::RightStickX), right_axis_x); | 274 | callbacks.on_stick_data(static_cast<int>(PadAxes::RightStickX), right_axis_x); |
| @@ -283,25 +283,25 @@ f32 JoyconPoller::GetAxisValue(u16 raw_value, Joycon::JoyStickAxisCalibration ca | |||
| 283 | return value / calibration.min; | 283 | return value / calibration.min; |
| 284 | } | 284 | } |
| 285 | 285 | ||
| 286 | std::pair<f32, f32> JoyconPoller::GetPassiveAxisValue(PasivePadStick raw_value) const { | 286 | std::pair<f32, f32> JoyconPoller::GetPassiveAxisValue(PassivePadStick raw_value) const { |
| 287 | switch (raw_value) { | 287 | switch (raw_value) { |
| 288 | case PasivePadStick::Right: | 288 | case PassivePadStick::Right: |
| 289 | return {1.0f, 0.0f}; | 289 | return {1.0f, 0.0f}; |
| 290 | case PasivePadStick::RightDown: | 290 | case PassivePadStick::RightDown: |
| 291 | return {1.0f, -1.0f}; | 291 | return {1.0f, -1.0f}; |
| 292 | case PasivePadStick::Down: | 292 | case PassivePadStick::Down: |
| 293 | return {0.0f, -1.0f}; | 293 | return {0.0f, -1.0f}; |
| 294 | case PasivePadStick::DownLeft: | 294 | case PassivePadStick::DownLeft: |
| 295 | return {-1.0f, -1.0f}; | 295 | return {-1.0f, -1.0f}; |
| 296 | case PasivePadStick::Left: | 296 | case PassivePadStick::Left: |
| 297 | return {-1.0f, 0.0f}; | 297 | return {-1.0f, 0.0f}; |
| 298 | case PasivePadStick::LeftUp: | 298 | case PassivePadStick::LeftUp: |
| 299 | return {-1.0f, 1.0f}; | 299 | return {-1.0f, 1.0f}; |
| 300 | case PasivePadStick::Up: | 300 | case PassivePadStick::Up: |
| 301 | return {0.0f, 1.0f}; | 301 | return {0.0f, 1.0f}; |
| 302 | case PasivePadStick::UpRight: | 302 | case PassivePadStick::UpRight: |
| 303 | return {1.0f, 1.0f}; | 303 | return {1.0f, 1.0f}; |
| 304 | case PasivePadStick::Neutral: | 304 | case PassivePadStick::Neutral: |
| 305 | default: | 305 | default: |
| 306 | return {0.0f, 0.0f}; | 306 | return {0.0f, 0.0f}; |
| 307 | } | 307 | } |
diff --git a/src/input_common/helpers/joycon_protocol/poller.h b/src/input_common/helpers/joycon_protocol/poller.h index 5c897f070..0fa72c6db 100644 --- a/src/input_common/helpers/joycon_protocol/poller.h +++ b/src/input_common/helpers/joycon_protocol/poller.h | |||
| @@ -46,15 +46,15 @@ private: | |||
| 46 | const MotionStatus& motion_status); | 46 | const MotionStatus& motion_status); |
| 47 | void UpdateActiveProPadInput(const InputReportActive& input, const MotionStatus& motion_status); | 47 | void UpdateActiveProPadInput(const InputReportActive& input, const MotionStatus& motion_status); |
| 48 | 48 | ||
| 49 | void UpdatePasiveLeftPadInput(const InputReportPassive& buffer); | 49 | void UpdatePassiveLeftPadInput(const InputReportPassive& buffer); |
| 50 | void UpdatePasiveRightPadInput(const InputReportPassive& buffer); | 50 | void UpdatePassiveRightPadInput(const InputReportPassive& buffer); |
| 51 | void UpdatePasiveProPadInput(const InputReportPassive& buffer); | 51 | void UpdatePassiveProPadInput(const InputReportPassive& buffer); |
| 52 | 52 | ||
| 53 | /// Returns a calibrated joystick axis from raw axis data | 53 | /// Returns a calibrated joystick axis from raw axis data |
| 54 | f32 GetAxisValue(u16 raw_value, JoyStickAxisCalibration calibration) const; | 54 | f32 GetAxisValue(u16 raw_value, JoyStickAxisCalibration calibration) const; |
| 55 | 55 | ||
| 56 | /// Returns a digital joystick axis from passive axis data | 56 | /// Returns a digital joystick axis from passive axis data |
| 57 | std::pair<f32, f32> GetPassiveAxisValue(PasivePadStick raw_value) const; | 57 | std::pair<f32, f32> GetPassiveAxisValue(PassivePadStick raw_value) const; |
| 58 | 58 | ||
| 59 | /// Returns a calibrated accelerometer axis from raw motion data | 59 | /// Returns a calibrated accelerometer axis from raw motion data |
| 60 | f32 GetAccelerometerValue(s16 raw, const MotionSensorCalibration& cal, | 60 | f32 GetAccelerometerValue(s16 raw, const MotionSensorCalibration& cal, |
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 7024a19cf..2e7f9c5ed 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp | |||
| @@ -197,7 +197,7 @@ struct GPU::Impl { | |||
| 197 | constexpr u64 gpu_ticks_num = 384; | 197 | constexpr u64 gpu_ticks_num = 384; |
| 198 | constexpr u64 gpu_ticks_den = 625; | 198 | constexpr u64 gpu_ticks_den = 625; |
| 199 | 199 | ||
| 200 | u64 nanoseconds = system.CoreTiming().GetGlobalTimeNs().count(); | 200 | u64 nanoseconds = system.CoreTiming().GetCPUTimeNs().count(); |
| 201 | if (Settings::values.use_fast_gpu_time.GetValue()) { | 201 | if (Settings::values.use_fast_gpu_time.GetValue()) { |
| 202 | nanoseconds /= 256; | 202 | nanoseconds /= 256; |
| 203 | } | 203 | } |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index b047e7b3d..d3eabd686 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp | |||
| @@ -112,13 +112,17 @@ GLenum ImageTarget(Shader::TextureType type, int num_samples = 1) { | |||
| 112 | return GL_NONE; | 112 | return GL_NONE; |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | GLenum TextureMode(PixelFormat format, bool is_first) { | 115 | GLenum TextureMode(PixelFormat format, std::array<SwizzleSource, 4> swizzle) { |
| 116 | bool any_r = | ||
| 117 | std::ranges::any_of(swizzle, [](SwizzleSource s) { return s == SwizzleSource::R; }); | ||
| 116 | switch (format) { | 118 | switch (format) { |
| 117 | case PixelFormat::D24_UNORM_S8_UINT: | 119 | case PixelFormat::D24_UNORM_S8_UINT: |
| 118 | case PixelFormat::D32_FLOAT_S8_UINT: | 120 | case PixelFormat::D32_FLOAT_S8_UINT: |
| 119 | return is_first ? GL_DEPTH_COMPONENT : GL_STENCIL_INDEX; | 121 | // R = depth, G = stencil |
| 122 | return any_r ? GL_DEPTH_COMPONENT : GL_STENCIL_INDEX; | ||
| 120 | case PixelFormat::S8_UINT_D24_UNORM: | 123 | case PixelFormat::S8_UINT_D24_UNORM: |
| 121 | return is_first ? GL_STENCIL_INDEX : GL_DEPTH_COMPONENT; | 124 | // R = stencil, G = depth |
| 125 | return any_r ? GL_STENCIL_INDEX : GL_DEPTH_COMPONENT; | ||
| 122 | default: | 126 | default: |
| 123 | ASSERT(false); | 127 | ASSERT(false); |
| 124 | return GL_DEPTH_COMPONENT; | 128 | return GL_DEPTH_COMPONENT; |
| @@ -208,8 +212,7 @@ void ApplySwizzle(GLuint handle, PixelFormat format, std::array<SwizzleSource, 4 | |||
| 208 | case PixelFormat::D32_FLOAT_S8_UINT: | 212 | case PixelFormat::D32_FLOAT_S8_UINT: |
| 209 | case PixelFormat::S8_UINT_D24_UNORM: | 213 | case PixelFormat::S8_UINT_D24_UNORM: |
| 210 | UNIMPLEMENTED_IF(swizzle[0] != SwizzleSource::R && swizzle[0] != SwizzleSource::G); | 214 | UNIMPLEMENTED_IF(swizzle[0] != SwizzleSource::R && swizzle[0] != SwizzleSource::G); |
| 211 | glTextureParameteri(handle, GL_DEPTH_STENCIL_TEXTURE_MODE, | 215 | glTextureParameteri(handle, GL_DEPTH_STENCIL_TEXTURE_MODE, TextureMode(format, swizzle)); |
| 212 | TextureMode(format, swizzle[0] == SwizzleSource::R)); | ||
| 213 | std::ranges::transform(swizzle, swizzle.begin(), ConvertGreenRed); | 216 | std::ranges::transform(swizzle, swizzle.begin(), ConvertGreenRed); |
| 214 | break; | 217 | break; |
| 215 | case PixelFormat::A5B5G5R1_UNORM: { | 218 | case PixelFormat::A5B5G5R1_UNORM: { |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index b0153a502..9cbcb3c8f 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp | |||
| @@ -238,7 +238,7 @@ private: | |||
| 238 | return indices; | 238 | return indices; |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | void MakeAndUpdateIndices(u8* staging_data, size_t quad_size, u32 quad, u32 first) { | 241 | void MakeAndUpdateIndices(u8* staging_data, size_t quad_size, u32 quad, u32 first) override { |
| 242 | switch (index_type) { | 242 | switch (index_type) { |
| 243 | case VK_INDEX_TYPE_UINT8_EXT: | 243 | case VK_INDEX_TYPE_UINT8_EXT: |
| 244 | std::memcpy(staging_data, MakeIndices<u8>(quad, first).data(), quad_size); | 244 | std::memcpy(staging_data, MakeIndices<u8>(quad, first).data(), quad_size); |
| @@ -278,7 +278,7 @@ private: | |||
| 278 | return indices; | 278 | return indices; |
| 279 | } | 279 | } |
| 280 | 280 | ||
| 281 | void MakeAndUpdateIndices(u8* staging_data, size_t quad_size, u32 quad, u32 first) { | 281 | void MakeAndUpdateIndices(u8* staging_data, size_t quad_size, u32 quad, u32 first) override { |
| 282 | switch (index_type) { | 282 | switch (index_type) { |
| 283 | case VK_INDEX_TYPE_UINT8_EXT: | 283 | case VK_INDEX_TYPE_UINT8_EXT: |
| 284 | std::memcpy(staging_data, MakeIndices<u8>(quad, first).data(), quad_size); | 284 | std::memcpy(staging_data, MakeIndices<u8>(quad, first).data(), quad_size); |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index f085d53a1..25965b684 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -1294,7 +1294,7 @@ void RasterizerVulkan::UpdateDepthBoundsTestEnable(Tegra::Engines::Maxwell3D::Re | |||
| 1294 | LOG_WARNING(Render_Vulkan, "Depth bounds is enabled but not supported"); | 1294 | LOG_WARNING(Render_Vulkan, "Depth bounds is enabled but not supported"); |
| 1295 | enabled = false; | 1295 | enabled = false; |
| 1296 | } | 1296 | } |
| 1297 | scheduler.Record([enable = regs.depth_bounds_enable](vk::CommandBuffer cmdbuf) { | 1297 | scheduler.Record([enable = enabled](vk::CommandBuffer cmdbuf) { |
| 1298 | cmdbuf.SetDepthBoundsTestEnableEXT(enable); | 1298 | cmdbuf.SetDepthBoundsTestEnableEXT(enable); |
| 1299 | }); | 1299 | }); |
| 1300 | } | 1300 | } |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 8a204f93f..e013d1c60 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -189,13 +189,16 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { | |||
| 189 | if (info.IsRenderTarget()) { | 189 | if (info.IsRenderTarget()) { |
| 190 | return ImageAspectMask(info.format); | 190 | return ImageAspectMask(info.format); |
| 191 | } | 191 | } |
| 192 | const bool is_first = info.Swizzle()[0] == SwizzleSource::R; | 192 | bool any_r = |
| 193 | std::ranges::any_of(info.Swizzle(), [](SwizzleSource s) { return s == SwizzleSource::R; }); | ||
| 193 | switch (info.format) { | 194 | switch (info.format) { |
| 194 | case PixelFormat::D24_UNORM_S8_UINT: | 195 | case PixelFormat::D24_UNORM_S8_UINT: |
| 195 | case PixelFormat::D32_FLOAT_S8_UINT: | 196 | case PixelFormat::D32_FLOAT_S8_UINT: |
| 196 | return is_first ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT; | 197 | // R = depth, G = stencil |
| 198 | return any_r ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_STENCIL_BIT; | ||
| 197 | case PixelFormat::S8_UINT_D24_UNORM: | 199 | case PixelFormat::S8_UINT_D24_UNORM: |
| 198 | return is_first ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; | 200 | // R = stencil, G = depth |
| 201 | return any_r ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; | ||
| 199 | case PixelFormat::D16_UNORM: | 202 | case PixelFormat::D16_UNORM: |
| 200 | case PixelFormat::D32_FLOAT: | 203 | case PixelFormat::D32_FLOAT: |
| 201 | return VK_IMAGE_ASPECT_DEPTH_BIT; | 204 | return VK_IMAGE_ASPECT_DEPTH_BIT; |
| @@ -1769,7 +1772,7 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t | |||
| 1769 | .minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(), | 1772 | .minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(), |
| 1770 | .maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(), | 1773 | .maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(), |
| 1771 | .borderColor = | 1774 | .borderColor = |
| 1772 | arbitrary_borders ? VK_BORDER_COLOR_INT_CUSTOM_EXT : ConvertBorderColor(color), | 1775 | arbitrary_borders ? VK_BORDER_COLOR_FLOAT_CUSTOM_EXT : ConvertBorderColor(color), |
| 1773 | .unnormalizedCoordinates = VK_FALSE, | 1776 | .unnormalizedCoordinates = VK_FALSE, |
| 1774 | }); | 1777 | }); |
| 1775 | } | 1778 | } |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f233b065e..c092507f4 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -91,6 +91,9 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual | |||
| 91 | #include "common/microprofile.h" | 91 | #include "common/microprofile.h" |
| 92 | #include "common/scm_rev.h" | 92 | #include "common/scm_rev.h" |
| 93 | #include "common/scope_exit.h" | 93 | #include "common/scope_exit.h" |
| 94 | #ifdef _WIN32 | ||
| 95 | #include "common/windows/timer_resolution.h" | ||
| 96 | #endif | ||
| 94 | #ifdef ARCHITECTURE_x86_64 | 97 | #ifdef ARCHITECTURE_x86_64 |
| 95 | #include "common/x64/cpu_detect.h" | 98 | #include "common/x64/cpu_detect.h" |
| 96 | #endif | 99 | #endif |
| @@ -377,6 +380,12 @@ GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan | |||
| 377 | LOG_INFO(Frontend, "Host RAM: {:.2f} GiB", | 380 | LOG_INFO(Frontend, "Host RAM: {:.2f} GiB", |
| 378 | Common::GetMemInfo().TotalPhysicalMemory / f64{1_GiB}); | 381 | Common::GetMemInfo().TotalPhysicalMemory / f64{1_GiB}); |
| 379 | LOG_INFO(Frontend, "Host Swap: {:.2f} GiB", Common::GetMemInfo().TotalSwapMemory / f64{1_GiB}); | 382 | LOG_INFO(Frontend, "Host Swap: {:.2f} GiB", Common::GetMemInfo().TotalSwapMemory / f64{1_GiB}); |
| 383 | #ifdef _WIN32 | ||
| 384 | LOG_INFO(Frontend, "Host Timer Resolution: {:.4f} ms", | ||
| 385 | std::chrono::duration_cast<std::chrono::duration<f64, std::milli>>( | ||
| 386 | Common::Windows::SetCurrentTimerResolutionToMaximum()) | ||
| 387 | .count()); | ||
| 388 | #endif | ||
| 380 | UpdateWindowTitle(); | 389 | UpdateWindowTitle(); |
| 381 | 390 | ||
| 382 | show(); | 391 | show(); |
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 77edd58ca..5f39ece32 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -42,6 +42,8 @@ | |||
| 42 | #include <windows.h> | 42 | #include <windows.h> |
| 43 | 43 | ||
| 44 | #include <shellapi.h> | 44 | #include <shellapi.h> |
| 45 | |||
| 46 | #include "common/windows/timer_resolution.h" | ||
| 45 | #endif | 47 | #endif |
| 46 | 48 | ||
| 47 | #undef _UNICODE | 49 | #undef _UNICODE |
| @@ -314,6 +316,8 @@ int main(int argc, char** argv) { | |||
| 314 | 316 | ||
| 315 | #ifdef _WIN32 | 317 | #ifdef _WIN32 |
| 316 | LocalFree(argv_w); | 318 | LocalFree(argv_w); |
| 319 | |||
| 320 | Common::Windows::SetCurrentTimerResolutionToMaximum(); | ||
| 317 | #endif | 321 | #endif |
| 318 | 322 | ||
| 319 | MicroProfileOnThreadCreate("EmuThread"); | 323 | MicroProfileOnThreadCreate("EmuThread"); |