diff options
| author | 2023-10-08 11:32:32 -0400 | |
|---|---|---|
| committer | 2023-10-08 12:54:23 -0400 | |
| commit | 21bc2c14bc7408427a8b4851a7a3f15251f2afa8 (patch) | |
| tree | 69597208c660a1af323b7e6dc5ff8e804e555682 /src | |
| parent | Merge pull request #11656 from liamwhite/recreate-surface-automatically (diff) | |
| download | yuzu-21bc2c14bc7408427a8b4851a7a3f15251f2afa8.tar.gz yuzu-21bc2c14bc7408427a8b4851a7a3f15251f2afa8.tar.xz yuzu-21bc2c14bc7408427a8b4851a7a3f15251f2afa8.zip | |
common: add arm64 native clock
Diffstat (limited to 'src')
| -rw-r--r-- | src/common/CMakeLists.txt | 8 | ||||
| -rw-r--r-- | src/common/arm64/native_clock.cpp | 72 | ||||
| -rw-r--r-- | src/common/arm64/native_clock.h | 47 | ||||
| -rw-r--r-- | src/common/wall_clock.cpp | 8 |
4 files changed, 134 insertions, 1 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 416203c59..8a1861051 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -189,6 +189,14 @@ if(ARCHITECTURE_x86_64) | |||
| 189 | target_link_libraries(common PRIVATE xbyak::xbyak) | 189 | target_link_libraries(common PRIVATE xbyak::xbyak) |
| 190 | endif() | 190 | endif() |
| 191 | 191 | ||
| 192 | if (ARCHITECTURE_arm64 AND (ANDROID OR LINUX)) | ||
| 193 | target_sources(common | ||
| 194 | PRIVATE | ||
| 195 | arm64/native_clock.cpp | ||
| 196 | arm64/native_clock.h | ||
| 197 | ) | ||
| 198 | endif() | ||
| 199 | |||
| 192 | if (MSVC) | 200 | if (MSVC) |
| 193 | target_compile_definitions(common PRIVATE | 201 | target_compile_definitions(common PRIVATE |
| 194 | # The standard library doesn't provide any replacement for codecvt yet | 202 | # The standard library doesn't provide any replacement for codecvt yet |
diff --git a/src/common/arm64/native_clock.cpp b/src/common/arm64/native_clock.cpp new file mode 100644 index 000000000..88fdba527 --- /dev/null +++ b/src/common/arm64/native_clock.cpp | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/arm64/native_clock.h" | ||
| 5 | |||
| 6 | namespace Common::Arm64 { | ||
| 7 | |||
| 8 | namespace { | ||
| 9 | |||
| 10 | NativeClock::FactorType GetFixedPointFactor(u64 num, u64 den) { | ||
| 11 | return (static_cast<NativeClock::FactorType>(num) << 64) / den; | ||
| 12 | } | ||
| 13 | |||
| 14 | u64 MultiplyHigh(u64 m, NativeClock::FactorType factor) { | ||
| 15 | return static_cast<u64>((m * factor) >> 64); | ||
| 16 | } | ||
| 17 | |||
| 18 | } // namespace | ||
| 19 | |||
| 20 | NativeClock::NativeClock() { | ||
| 21 | const u64 host_cntfrq = GetHostCNTFRQ(); | ||
| 22 | ns_cntfrq_factor = GetFixedPointFactor(NsRatio::den, host_cntfrq); | ||
| 23 | us_cntfrq_factor = GetFixedPointFactor(UsRatio::den, host_cntfrq); | ||
| 24 | ms_cntfrq_factor = GetFixedPointFactor(MsRatio::den, host_cntfrq); | ||
| 25 | guest_cntfrq_factor = GetFixedPointFactor(CNTFRQ, host_cntfrq); | ||
| 26 | gputick_cntfrq_factor = GetFixedPointFactor(GPUTickFreq, host_cntfrq); | ||
| 27 | } | ||
| 28 | |||
| 29 | std::chrono::nanoseconds NativeClock::GetTimeNS() const { | ||
| 30 | return std::chrono::nanoseconds{MultiplyHigh(GetHostTicksElapsed(), ns_cntfrq_factor)}; | ||
| 31 | } | ||
| 32 | |||
| 33 | std::chrono::microseconds NativeClock::GetTimeUS() const { | ||
| 34 | return std::chrono::microseconds{MultiplyHigh(GetHostTicksElapsed(), us_cntfrq_factor)}; | ||
| 35 | } | ||
| 36 | |||
| 37 | std::chrono::milliseconds NativeClock::GetTimeMS() const { | ||
| 38 | return std::chrono::milliseconds{MultiplyHigh(GetHostTicksElapsed(), ms_cntfrq_factor)}; | ||
| 39 | } | ||
| 40 | |||
| 41 | u64 NativeClock::GetCNTPCT() const { | ||
| 42 | return MultiplyHigh(GetHostTicksElapsed(), guest_cntfrq_factor); | ||
| 43 | } | ||
| 44 | |||
| 45 | u64 NativeClock::GetGPUTick() const { | ||
| 46 | return MultiplyHigh(GetHostTicksElapsed(), gputick_cntfrq_factor); | ||
| 47 | } | ||
| 48 | |||
| 49 | u64 NativeClock::GetHostTicksNow() const { | ||
| 50 | u64 cntvct_el0 = 0; | ||
| 51 | asm volatile("dsb ish\n\t" | ||
| 52 | "mrs %[cntvct_el0], cntvct_el0\n\t" | ||
| 53 | "dsb ish\n\t" | ||
| 54 | : [cntvct_el0] "=r"(cntvct_el0)); | ||
| 55 | return cntvct_el0; | ||
| 56 | } | ||
| 57 | |||
| 58 | u64 NativeClock::GetHostTicksElapsed() const { | ||
| 59 | return GetHostTicksNow(); | ||
| 60 | } | ||
| 61 | |||
| 62 | bool NativeClock::IsNative() const { | ||
| 63 | return true; | ||
| 64 | } | ||
| 65 | |||
| 66 | u64 NativeClock::GetHostCNTFRQ() { | ||
| 67 | u64 cntfrq_el0 = 0; | ||
| 68 | asm("mrs %[cntfrq_el0], cntfrq_el0" : [cntfrq_el0] "=r"(cntfrq_el0)); | ||
| 69 | return cntfrq_el0; | ||
| 70 | } | ||
| 71 | |||
| 72 | } // namespace Common::Arm64 | ||
diff --git a/src/common/arm64/native_clock.h b/src/common/arm64/native_clock.h new file mode 100644 index 000000000..a28b419f2 --- /dev/null +++ b/src/common/arm64/native_clock.h | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "common/wall_clock.h" | ||
| 7 | |||
| 8 | namespace Common::Arm64 { | ||
| 9 | |||
| 10 | class NativeClock final : public WallClock { | ||
| 11 | public: | ||
| 12 | explicit NativeClock(); | ||
| 13 | |||
| 14 | std::chrono::nanoseconds GetTimeNS() const override; | ||
| 15 | |||
| 16 | std::chrono::microseconds GetTimeUS() const override; | ||
| 17 | |||
| 18 | std::chrono::milliseconds GetTimeMS() const override; | ||
| 19 | |||
| 20 | u64 GetCNTPCT() const override; | ||
| 21 | |||
| 22 | u64 GetGPUTick() const override; | ||
| 23 | |||
| 24 | u64 GetHostTicksNow() const override; | ||
| 25 | |||
| 26 | u64 GetHostTicksElapsed() const override; | ||
| 27 | |||
| 28 | bool IsNative() const override; | ||
| 29 | |||
| 30 | static u64 GetHostCNTFRQ(); | ||
| 31 | |||
| 32 | public: | ||
| 33 | using FactorType = unsigned __int128; | ||
| 34 | |||
| 35 | FactorType GetGuestCNTFRQFactor() const { | ||
| 36 | return guest_cntfrq_factor; | ||
| 37 | } | ||
| 38 | |||
| 39 | private: | ||
| 40 | FactorType ns_cntfrq_factor; | ||
| 41 | FactorType us_cntfrq_factor; | ||
| 42 | FactorType ms_cntfrq_factor; | ||
| 43 | FactorType guest_cntfrq_factor; | ||
| 44 | FactorType gputick_cntfrq_factor; | ||
| 45 | }; | ||
| 46 | |||
| 47 | } // namespace Common::Arm64 | ||
diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp index 71e15ab4c..caca9a123 100644 --- a/src/common/wall_clock.cpp +++ b/src/common/wall_clock.cpp | |||
| @@ -10,6 +10,10 @@ | |||
| 10 | #include "common/x64/rdtsc.h" | 10 | #include "common/x64/rdtsc.h" |
| 11 | #endif | 11 | #endif |
| 12 | 12 | ||
| 13 | #if defined(ARCHITECTURE_arm64) && defined(__linux__) | ||
| 14 | #include "common/arm64/native_clock.h" | ||
| 15 | #endif | ||
| 16 | |||
| 13 | namespace Common { | 17 | namespace Common { |
| 14 | 18 | ||
| 15 | class StandardWallClock final : public WallClock { | 19 | class StandardWallClock final : public WallClock { |
| @@ -53,7 +57,7 @@ private: | |||
| 53 | }; | 57 | }; |
| 54 | 58 | ||
| 55 | std::unique_ptr<WallClock> CreateOptimalClock() { | 59 | std::unique_ptr<WallClock> CreateOptimalClock() { |
| 56 | #ifdef ARCHITECTURE_x86_64 | 60 | #if defined(ARCHITECTURE_x86_64) |
| 57 | const auto& caps = GetCPUCaps(); | 61 | const auto& caps = GetCPUCaps(); |
| 58 | 62 | ||
| 59 | if (caps.invariant_tsc && caps.tsc_frequency >= std::nano::den) { | 63 | if (caps.invariant_tsc && caps.tsc_frequency >= std::nano::den) { |
| @@ -64,6 +68,8 @@ std::unique_ptr<WallClock> CreateOptimalClock() { | |||
| 64 | // - Is not more precise than 1 GHz (1ns resolution) | 68 | // - Is not more precise than 1 GHz (1ns resolution) |
| 65 | return std::make_unique<StandardWallClock>(); | 69 | return std::make_unique<StandardWallClock>(); |
| 66 | } | 70 | } |
| 71 | #elif defined(ARCHITECTURE_arm64) && defined(__linux__) | ||
| 72 | return std::make_unique<Arm64::NativeClock>(); | ||
| 67 | #else | 73 | #else |
| 68 | return std::make_unique<StandardWallClock>(); | 74 | return std::make_unique<StandardWallClock>(); |
| 69 | #endif | 75 | #endif |