Browse Source
[common] remove ptr indirection on WallClock (#3864)
[common] remove ptr indirection on WallClock (#3864)
also devirtualizes manually since compiler doesn't do it with LTO Signed-off-by: lizzie <lizzie@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3864 Reviewed-by: crueter <crueter@eden-emu.dev>lizzie/stable-shader-pools
committed by
crueter
No known key found for this signature in database
GPG Key ID: 425ACD2D4830EBC6
14 changed files with 288 additions and 392 deletions
-
6src/common/CMakeLists.txt
-
87src/common/arm64/native_clock.cpp
-
45src/common/arm64/native_clock.h
-
205src/common/wall_clock.cpp
-
45src/common/wall_clock.h
-
46src/common/x64/native_clock.cpp
-
38src/common/x64/native_clock.h
-
9src/core/arm/dynarmic/arm_dynarmic_32.cpp
-
6src/core/arm/dynarmic/arm_dynarmic_64.cpp
-
8src/core/arm/nce/patcher.cpp
-
155src/core/core_timing.cpp
-
18src/core/core_timing.h
-
9src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
-
3src/core/hle/service/nvnflinger/buffer_queue_producer.h
@ -1,87 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#ifdef ANDROID
|
|||
#include <sys/system_properties.h>
|
|||
#endif
|
|||
#include "common/arm64/native_clock.h"
|
|||
|
|||
namespace Common::Arm64 { |
|||
|
|||
namespace { |
|||
|
|||
NativeClock::FactorType GetFixedPointFactor(u64 num, u64 den) { |
|||
return (static_cast<NativeClock::FactorType>(num) << 64) / den; |
|||
} |
|||
|
|||
u64 MultiplyHigh(u64 m, NativeClock::FactorType factor) { |
|||
return static_cast<u64>((m * factor) >> 64); |
|||
} |
|||
|
|||
} // namespace
|
|||
|
|||
NativeClock::NativeClock() { |
|||
const u64 host_cntfrq = GetHostCNTFRQ(); |
|||
ns_cntfrq_factor = GetFixedPointFactor(NsRatio::den, host_cntfrq); |
|||
us_cntfrq_factor = GetFixedPointFactor(UsRatio::den, host_cntfrq); |
|||
ms_cntfrq_factor = GetFixedPointFactor(MsRatio::den, host_cntfrq); |
|||
guest_cntfrq_factor = GetFixedPointFactor(CNTFRQ, host_cntfrq); |
|||
gputick_cntfrq_factor = GetFixedPointFactor(GPUTickFreq, host_cntfrq); |
|||
} |
|||
|
|||
std::chrono::nanoseconds NativeClock::GetTimeNS() const { |
|||
return std::chrono::nanoseconds{MultiplyHigh(GetUptime(), ns_cntfrq_factor)}; |
|||
} |
|||
|
|||
std::chrono::microseconds NativeClock::GetTimeUS() const { |
|||
return std::chrono::microseconds{MultiplyHigh(GetUptime(), us_cntfrq_factor)}; |
|||
} |
|||
|
|||
std::chrono::milliseconds NativeClock::GetTimeMS() const { |
|||
return std::chrono::milliseconds{MultiplyHigh(GetUptime(), ms_cntfrq_factor)}; |
|||
} |
|||
|
|||
s64 NativeClock::GetCNTPCT() const { |
|||
return MultiplyHigh(GetUptime(), guest_cntfrq_factor); |
|||
} |
|||
|
|||
s64 NativeClock::GetGPUTick() const { |
|||
return MultiplyHigh(GetUptime(), gputick_cntfrq_factor); |
|||
} |
|||
|
|||
s64 NativeClock::GetUptime() const { |
|||
s64 cntvct_el0 = 0; |
|||
asm volatile("dsb ish\n\t" |
|||
"mrs %[cntvct_el0], cntvct_el0\n\t" |
|||
"dsb ish\n\t" |
|||
: [cntvct_el0] "=r"(cntvct_el0)); |
|||
return cntvct_el0; |
|||
} |
|||
|
|||
bool NativeClock::IsNative() const { |
|||
return true; |
|||
} |
|||
|
|||
s64 NativeClock::GetHostCNTFRQ() { |
|||
u64 cntfrq_el0 = 0; |
|||
std::string_view board{""}; |
|||
#ifdef ANDROID
|
|||
char buffer[PROP_VALUE_MAX]; |
|||
int len{__system_property_get("ro.product.board", buffer)}; |
|||
board = std::string_view(buffer, static_cast<size_t>(len)); |
|||
#endif
|
|||
if (board == "s5e9925") { // Exynos 2200
|
|||
cntfrq_el0 = 25600000; |
|||
} else if (board == "exynos2100") { // Exynos 2100
|
|||
cntfrq_el0 = 26000000; |
|||
} else if (board == "exynos9810") { // Exynos 9810
|
|||
cntfrq_el0 = 26000000; |
|||
} else if (board == "s5e8825") { // Exynos 1280
|
|||
cntfrq_el0 = 26000000; |
|||
} else { |
|||
asm("mrs %[cntfrq_el0], cntfrq_el0" : [cntfrq_el0] "=r"(cntfrq_el0)); |
|||
} |
|||
return cntfrq_el0; |
|||
} |
|||
|
|||
} // namespace Common::Arm64
|
|||
@ -1,45 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "common/wall_clock.h" |
|||
|
|||
namespace Common::Arm64 { |
|||
|
|||
class NativeClock final : public WallClock { |
|||
public: |
|||
explicit NativeClock(); |
|||
|
|||
std::chrono::nanoseconds GetTimeNS() const override; |
|||
|
|||
std::chrono::microseconds GetTimeUS() const override; |
|||
|
|||
std::chrono::milliseconds GetTimeMS() const override; |
|||
|
|||
s64 GetCNTPCT() const override; |
|||
|
|||
s64 GetGPUTick() const override; |
|||
|
|||
s64 GetUptime() const override; |
|||
|
|||
bool IsNative() const override; |
|||
|
|||
static s64 GetHostCNTFRQ(); |
|||
|
|||
public: |
|||
using FactorType = unsigned __int128; |
|||
|
|||
FactorType GetGuestCNTFRQFactor() const { |
|||
return guest_cntfrq_factor; |
|||
} |
|||
|
|||
private: |
|||
FactorType ns_cntfrq_factor; |
|||
FactorType us_cntfrq_factor; |
|||
FactorType ms_cntfrq_factor; |
|||
FactorType guest_cntfrq_factor; |
|||
FactorType gputick_cntfrq_factor; |
|||
}; |
|||
|
|||
} // namespace Common::Arm64 |
|||
@ -1,77 +1,196 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|||
|
|||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "common/steady_clock.h"
|
|||
#include "common/uint128.h"
|
|||
#include "common/wall_clock.h"
|
|||
|
|||
#ifdef __ANDROID__
|
|||
#include <sys/system_properties.h>
|
|||
#endif
|
|||
#ifdef ARCHITECTURE_x86_64
|
|||
#include "common/x64/cpu_detect.h"
|
|||
#include "common/x64/native_clock.h"
|
|||
#include "common/x64/rdtsc.h"
|
|||
#endif
|
|||
#ifdef HAS_NCE
|
|||
#include "common/arm64/native_clock.h"
|
|||
#endif
|
|||
|
|||
namespace Common { |
|||
|
|||
class StandardWallClock final : public WallClock { |
|||
public: |
|||
explicit StandardWallClock() {} |
|||
#if defined(ARCHITECTURE_x86_64)
|
|||
WallClock::WallClock(bool invariant_, u64 rdtsc_frequency_) noexcept |
|||
: invariant{invariant_} |
|||
, rdtsc_frequency{rdtsc_frequency_} |
|||
, ns_rdtsc_factor{GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency_)} |
|||
, us_rdtsc_factor{GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency_)} |
|||
, ms_rdtsc_factor{GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency_)} |
|||
, cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency_)} |
|||
, gputick_rdtsc_factor{GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency_)} |
|||
{} |
|||
|
|||
std::chrono::nanoseconds GetTimeNS() const override { |
|||
return std::chrono::duration_cast<std::chrono::nanoseconds>( |
|||
std::chrono::system_clock::now().time_since_epoch()); |
|||
} |
|||
std::chrono::nanoseconds WallClock::GetTimeNS() const { |
|||
if (invariant) |
|||
return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()); |
|||
return std::chrono::nanoseconds{MultiplyHigh(GetUptime(), ns_rdtsc_factor)}; |
|||
} |
|||
|
|||
std::chrono::microseconds GetTimeUS() const override { |
|||
return std::chrono::duration_cast<std::chrono::microseconds>( |
|||
std::chrono::system_clock::now().time_since_epoch()); |
|||
} |
|||
std::chrono::microseconds WallClock::GetTimeUS() const { |
|||
if (invariant) |
|||
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()); |
|||
return std::chrono::microseconds{MultiplyHigh(GetUptime(), us_rdtsc_factor)}; |
|||
} |
|||
|
|||
std::chrono::milliseconds GetTimeMS() const override { |
|||
return std::chrono::duration_cast<std::chrono::milliseconds>( |
|||
std::chrono::system_clock::now().time_since_epoch()); |
|||
} |
|||
std::chrono::milliseconds WallClock::GetTimeMS() const { |
|||
if (invariant) |
|||
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()); |
|||
return std::chrono::milliseconds{MultiplyHigh(GetUptime(), ms_rdtsc_factor)}; |
|||
} |
|||
|
|||
s64 GetCNTPCT() const override { |
|||
s64 WallClock::GetCNTPCT() const { |
|||
if (invariant) |
|||
return GetUptime() * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den; |
|||
} |
|||
return MultiplyHigh(GetUptime(), cntpct_rdtsc_factor); |
|||
} |
|||
|
|||
s64 GetGPUTick() const override { |
|||
s64 WallClock::GetGPUTick() const { |
|||
if (invariant) |
|||
return GetUptime() * NsToGPUTickRatio::num / NsToGPUTickRatio::den; |
|||
} |
|||
return MultiplyHigh(GetUptime(), gputick_rdtsc_factor); |
|||
} |
|||
|
|||
s64 GetUptime() const override { |
|||
return std::chrono::duration_cast<std::chrono::nanoseconds>( |
|||
std::chrono::steady_clock::now().time_since_epoch()) |
|||
.count(); |
|||
} |
|||
s64 WallClock::GetUptime() const { |
|||
if (invariant) |
|||
return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch()).count(); |
|||
return s64(Common::X64::FencedRDTSC()); |
|||
} |
|||
|
|||
bool IsNative() const override { |
|||
bool WallClock::IsNative() const { |
|||
if (invariant) |
|||
return false; |
|||
} |
|||
}; |
|||
return true; |
|||
} |
|||
#elif defined(HAS_NCE)
|
|||
namespace { |
|||
|
|||
std::unique_ptr<WallClock> CreateOptimalClock() { |
|||
#if defined(ARCHITECTURE_x86_64)
|
|||
const auto& caps = GetCPUCaps(); |
|||
[[nodiscard]] WallClock::FactorType GetFixedPointFactor(u64 num, u64 den) noexcept { |
|||
return (WallClock::FactorType(num) << 64) / den; |
|||
} |
|||
|
|||
[[nodiscard]] u64 MultiplyHigh(u64 m, WallClock::FactorType factor) noexcept { |
|||
return static_cast<u64>((m * factor) >> 64); |
|||
} |
|||
|
|||
if (caps.invariant_tsc && caps.tsc_frequency >= std::nano::den) { |
|||
return std::make_unique<X64::NativeClock>(caps.tsc_frequency); |
|||
[[nodiscard]] s64 GetHostCNTFRQ() noexcept { |
|||
u64 cntfrq_el0 = 0; |
|||
#ifdef ANDROID
|
|||
std::string_view board{""}; |
|||
char buffer[PROP_VALUE_MAX]; |
|||
int len{__system_property_get("ro.product.board", buffer)}; |
|||
board = std::string_view(buffer, static_cast<size_t>(len)); |
|||
if (board == "s5e9925") { // Exynos 2200
|
|||
cntfrq_el0 = 25600000; |
|||
} else if (board == "exynos2100") { // Exynos 2100
|
|||
cntfrq_el0 = 26000000; |
|||
} else if (board == "exynos9810") { // Exynos 9810
|
|||
cntfrq_el0 = 26000000; |
|||
} else if (board == "s5e8825") { // Exynos 1280
|
|||
cntfrq_el0 = 26000000; |
|||
} else { |
|||
// Fallback to StandardWallClock if the hardware TSC
|
|||
// - Is not invariant
|
|||
// - Is not more precise than 1 GHz (1ns resolution)
|
|||
return std::make_unique<StandardWallClock>(); |
|||
asm volatile("mrs %[cntfrq_el0], cntfrq_el0" : [cntfrq_el0] "=r"(cntfrq_el0)); |
|||
} |
|||
return cntfrq_el0; |
|||
#else
|
|||
asm volatile("mrs %[cntfrq_el0], cntfrq_el0" : [cntfrq_el0] "=r"(cntfrq_el0)); |
|||
return cntfrq_el0; |
|||
#endif
|
|||
} |
|||
|
|||
} // namespace
|
|||
|
|||
WallClock::WallClock(bool invariant_, u64 rdtsc_frequency_) noexcept { |
|||
const u64 host_cntfrq = std::max<u64>(GetHostCNTFRQ(), 1); |
|||
ns_cntfrq_factor = GetFixedPointFactor(NsRatio::den, host_cntfrq); |
|||
us_cntfrq_factor = GetFixedPointFactor(UsRatio::den, host_cntfrq); |
|||
ms_cntfrq_factor = GetFixedPointFactor(MsRatio::den, host_cntfrq); |
|||
guest_cntfrq_factor = GetFixedPointFactor(CNTFRQ, host_cntfrq); |
|||
gputick_cntfrq_factor = GetFixedPointFactor(GPUTickFreq, host_cntfrq); |
|||
} |
|||
|
|||
std::chrono::nanoseconds WallClock::GetTimeNS() const { |
|||
return std::chrono::nanoseconds{MultiplyHigh(GetUptime(), ns_cntfrq_factor)}; |
|||
} |
|||
|
|||
std::chrono::microseconds WallClock::GetTimeUS() const { |
|||
return std::chrono::microseconds{MultiplyHigh(GetUptime(), us_cntfrq_factor)}; |
|||
} |
|||
|
|||
std::chrono::milliseconds WallClock::GetTimeMS() const { |
|||
return std::chrono::milliseconds{MultiplyHigh(GetUptime(), ms_cntfrq_factor)}; |
|||
} |
|||
|
|||
s64 WallClock::GetCNTPCT() const { |
|||
return MultiplyHigh(GetUptime(), guest_cntfrq_factor); |
|||
} |
|||
|
|||
s64 WallClock::GetGPUTick() const { |
|||
return MultiplyHigh(GetUptime(), gputick_cntfrq_factor); |
|||
} |
|||
|
|||
s64 WallClock::GetUptime() const { |
|||
s64 cntvct_el0 = 0; |
|||
asm volatile( |
|||
"dsb ish\n\t" |
|||
"mrs %[cntvct_el0], cntvct_el0\n\t" |
|||
"dsb ish\n\t" |
|||
: [cntvct_el0] "=r"(cntvct_el0) |
|||
); |
|||
return cntvct_el0; |
|||
} |
|||
|
|||
bool WallClock::IsNative() const { |
|||
return true; |
|||
} |
|||
#else
|
|||
WallClock::WallClock(bool invariant_, u64 rdtsc_frequency_) noexcept {} |
|||
|
|||
std::chrono::nanoseconds WallClock::GetTimeNS() const { |
|||
return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()); |
|||
} |
|||
|
|||
std::chrono::microseconds WallClock::GetTimeUS() const { |
|||
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()); |
|||
} |
|||
|
|||
std::chrono::milliseconds WallClock::GetTimeMS() const { |
|||
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()); |
|||
} |
|||
|
|||
s64 WallClock::GetCNTPCT() const { |
|||
return GetUptime() * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den; |
|||
} |
|||
|
|||
s64 WallClock::GetGPUTick() const { |
|||
return GetUptime() * NsToGPUTickRatio::num / NsToGPUTickRatio::den; |
|||
} |
|||
|
|||
s64 WallClock::GetUptime() const { |
|||
return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch()).count(); |
|||
} |
|||
|
|||
bool WallClock::IsNative() const { |
|||
return false; |
|||
} |
|||
#endif
|
|||
|
|||
WallClock CreateOptimalClock() noexcept { |
|||
#if defined(ARCHITECTURE_x86_64)
|
|||
auto const& caps = GetCPUCaps(); |
|||
return WallClock(!(caps.invariant_tsc && caps.tsc_frequency >= std::nano::den), std::max<u64>(caps.tsc_frequency, 1)); |
|||
#elif defined(HAS_NCE)
|
|||
return std::make_unique<Arm64::NativeClock>(); |
|||
return WallClock(false, 1); |
|||
#else
|
|||
return std::make_unique<StandardWallClock>(); |
|||
return WallClock(true, 1); |
|||
#endif
|
|||
} |
|||
|
|||
|
|||
@ -1,46 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "common/uint128.h"
|
|||
#include "common/x64/native_clock.h"
|
|||
#include "common/x64/rdtsc.h"
|
|||
|
|||
namespace Common::X64 { |
|||
|
|||
NativeClock::NativeClock(u64 rdtsc_frequency_) |
|||
: rdtsc_frequency{rdtsc_frequency_}, ns_rdtsc_factor{GetFixedPoint64Factor(NsRatio::den, |
|||
rdtsc_frequency)}, |
|||
us_rdtsc_factor{GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency)}, |
|||
ms_rdtsc_factor{GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency)}, |
|||
cntpct_rdtsc_factor{GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency)}, |
|||
gputick_rdtsc_factor{GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency)} {} |
|||
|
|||
std::chrono::nanoseconds NativeClock::GetTimeNS() const { |
|||
return std::chrono::nanoseconds{MultiplyHigh(GetUptime(), ns_rdtsc_factor)}; |
|||
} |
|||
|
|||
std::chrono::microseconds NativeClock::GetTimeUS() const { |
|||
return std::chrono::microseconds{MultiplyHigh(GetUptime(), us_rdtsc_factor)}; |
|||
} |
|||
|
|||
std::chrono::milliseconds NativeClock::GetTimeMS() const { |
|||
return std::chrono::milliseconds{MultiplyHigh(GetUptime(), ms_rdtsc_factor)}; |
|||
} |
|||
|
|||
s64 NativeClock::GetCNTPCT() const { |
|||
return MultiplyHigh(GetUptime(), cntpct_rdtsc_factor); |
|||
} |
|||
|
|||
s64 NativeClock::GetGPUTick() const { |
|||
return MultiplyHigh(GetUptime(), gputick_rdtsc_factor); |
|||
} |
|||
|
|||
s64 NativeClock::GetUptime() const { |
|||
return static_cast<s64>(FencedRDTSC()); |
|||
} |
|||
|
|||
bool NativeClock::IsNative() const { |
|||
return true; |
|||
} |
|||
|
|||
} // namespace Common::X64
|
|||
@ -1,38 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "common/wall_clock.h" |
|||
|
|||
namespace Common::X64 { |
|||
|
|||
class NativeClock final : public WallClock { |
|||
public: |
|||
explicit NativeClock(u64 rdtsc_frequency_); |
|||
|
|||
std::chrono::nanoseconds GetTimeNS() const override; |
|||
|
|||
std::chrono::microseconds GetTimeUS() const override; |
|||
|
|||
std::chrono::milliseconds GetTimeMS() const override; |
|||
|
|||
s64 GetCNTPCT() const override; |
|||
|
|||
s64 GetGPUTick() const override; |
|||
|
|||
s64 GetUptime() const override; |
|||
|
|||
bool IsNative() const override; |
|||
|
|||
private: |
|||
u64 rdtsc_frequency; |
|||
|
|||
u64 ns_rdtsc_factor; |
|||
u64 us_rdtsc_factor; |
|||
u64 ms_rdtsc_factor; |
|||
u64 cntpct_rdtsc_factor; |
|||
u64 gputick_rdtsc_factor; |
|||
}; |
|||
|
|||
} // namespace Common::X64 |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue