summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Morph2023-04-23 00:01:08 -0400
committerGravatar Morph2023-06-07 21:44:42 -0400
commit8e56a84566036cfff0aa5c3d80ae1b051d2bd0bf (patch)
tree2bb7be86aafe9986811758b508a7581d2efe8ac4 /src
parentnvnflinger: Acquire lock prior to signaling the vsync variable (diff)
downloadyuzu-8e56a84566036cfff0aa5c3d80ae1b051d2bd0bf.tar.gz
yuzu-8e56a84566036cfff0aa5c3d80ae1b051d2bd0bf.tar.xz
yuzu-8e56a84566036cfff0aa5c3d80ae1b051d2bd0bf.zip
core_timing: Use CNTPCT as the guest CPU tick
Previously, we were mixing the raw CPU frequency and CNTFRQ. The raw CPU frequency (1020 MHz) should've never been used as CNTPCT (whose frequency is CNTFRQ) is the only counter available.
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/renderer/adsp/adsp.cpp1
-rw-r--r--src/audio_core/renderer/adsp/audio_renderer.cpp5
-rw-r--r--src/audio_core/renderer/adsp/command_list_processor.cpp1
-rw-r--r--src/audio_core/renderer/command/performance/performance.cpp15
-rw-r--r--src/audio_core/sink/sink_stream.cpp1
-rw-r--r--src/common/wall_clock.h17
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/core_timing.cpp35
-rw-r--r--src/core/core_timing.h11
-rw-r--r--src/core/core_timing_util.h58
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp5
-rw-r--r--src/core/hle/kernel/svc/svc_info.cpp4
-rw-r--r--src/core/hle/service/hid/hidbus.cpp1
-rw-r--r--src/video_core/gpu.cpp14
14 files changed, 47 insertions, 122 deletions
diff --git a/src/audio_core/renderer/adsp/adsp.cpp b/src/audio_core/renderer/adsp/adsp.cpp
index 74772fc50..b1db31e93 100644
--- a/src/audio_core/renderer/adsp/adsp.cpp
+++ b/src/audio_core/renderer/adsp/adsp.cpp
@@ -7,7 +7,6 @@
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core.h" 8#include "core/core.h"
9#include "core/core_timing.h" 9#include "core/core_timing.h"
10#include "core/core_timing_util.h"
11#include "core/memory.h" 10#include "core/memory.h"
12 11
13namespace AudioCore::AudioRenderer::ADSP { 12namespace AudioCore::AudioRenderer::ADSP {
diff --git a/src/audio_core/renderer/adsp/audio_renderer.cpp b/src/audio_core/renderer/adsp/audio_renderer.cpp
index 8bc39f9f9..9ca716b60 100644
--- a/src/audio_core/renderer/adsp/audio_renderer.cpp
+++ b/src/audio_core/renderer/adsp/audio_renderer.cpp
@@ -13,7 +13,6 @@
13#include "common/thread.h" 13#include "common/thread.h"
14#include "core/core.h" 14#include "core/core.h"
15#include "core/core_timing.h" 15#include "core/core_timing.h"
16#include "core/core_timing_util.h"
17 16
18MICROPROFILE_DEFINE(Audio_Renderer, "Audio", "DSP", MP_RGB(60, 19, 97)); 17MICROPROFILE_DEFINE(Audio_Renderer, "Audio", "DSP", MP_RGB(60, 19, 97));
19 18
@@ -144,6 +143,7 @@ void AudioRenderer::ThreadFunc(std::stop_token stop_token) {
144 143
145 mailbox->ADSPSendMessage(RenderMessage::AudioRenderer_InitializeOK); 144 mailbox->ADSPSendMessage(RenderMessage::AudioRenderer_InitializeOK);
146 145
146 // 0.12 seconds (2304000 / 19200000)
147 constexpr u64 max_process_time{2'304'000ULL}; 147 constexpr u64 max_process_time{2'304'000ULL};
148 148
149 while (!stop_token.stop_requested()) { 149 while (!stop_token.stop_requested()) {
@@ -184,8 +184,7 @@ void AudioRenderer::ThreadFunc(std::stop_token stop_token) {
184 u64 max_time{max_process_time}; 184 u64 max_time{max_process_time};
185 if (index == 1 && command_buffer.applet_resource_user_id == 185 if (index == 1 && command_buffer.applet_resource_user_id ==
186 mailbox->GetCommandBuffer(0).applet_resource_user_id) { 186 mailbox->GetCommandBuffer(0).applet_resource_user_id) {
187 max_time = max_process_time - 187 max_time = max_process_time - render_times_taken[0];
188 Core::Timing::CyclesToNs(render_times_taken[0]).count();
189 if (render_times_taken[0] > max_process_time) { 188 if (render_times_taken[0] > max_process_time) {
190 max_time = 0; 189 max_time = 0;
191 } 190 }
diff --git a/src/audio_core/renderer/adsp/command_list_processor.cpp b/src/audio_core/renderer/adsp/command_list_processor.cpp
index 7a300d216..3a0f1ae38 100644
--- a/src/audio_core/renderer/adsp/command_list_processor.cpp
+++ b/src/audio_core/renderer/adsp/command_list_processor.cpp
@@ -9,7 +9,6 @@
9#include "common/settings.h" 9#include "common/settings.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/core_timing.h" 11#include "core/core_timing.h"
12#include "core/core_timing_util.h"
13#include "core/memory.h" 12#include "core/memory.h"
14 13
15namespace AudioCore::AudioRenderer::ADSP { 14namespace AudioCore::AudioRenderer::ADSP {
diff --git a/src/audio_core/renderer/command/performance/performance.cpp b/src/audio_core/renderer/command/performance/performance.cpp
index 985958b03..4a881547f 100644
--- a/src/audio_core/renderer/command/performance/performance.cpp
+++ b/src/audio_core/renderer/command/performance/performance.cpp
@@ -5,7 +5,6 @@
5#include "audio_core/renderer/command/performance/performance.h" 5#include "audio_core/renderer/command/performance/performance.h"
6#include "core/core.h" 6#include "core/core.h"
7#include "core/core_timing.h" 7#include "core/core_timing.h"
8#include "core/core_timing_util.h"
9 8
10namespace AudioCore::AudioRenderer { 9namespace AudioCore::AudioRenderer {
11 10
@@ -18,20 +17,18 @@ void PerformanceCommand::Process(const ADSP::CommandListProcessor& processor) {
18 auto base{entry_address.translated_address}; 17 auto base{entry_address.translated_address};
19 if (state == PerformanceState::Start) { 18 if (state == PerformanceState::Start) {
20 auto start_time_ptr{reinterpret_cast<u32*>(base + entry_address.entry_start_time_offset)}; 19 auto start_time_ptr{reinterpret_cast<u32*>(base + entry_address.entry_start_time_offset)};
21 *start_time_ptr = static_cast<u32>( 20 *start_time_ptr =
22 Core::Timing::CyclesToUs(processor.system->CoreTiming().GetClockTicks() - 21 static_cast<u32>(processor.system->CoreTiming().GetClockTicks() - processor.start_time -
23 processor.start_time - processor.current_processing_time) 22 processor.current_processing_time);
24 .count());
25 } else if (state == PerformanceState::Stop) { 23 } else if (state == PerformanceState::Stop) {
26 auto processed_time_ptr{ 24 auto processed_time_ptr{
27 reinterpret_cast<u32*>(base + entry_address.entry_processed_time_offset)}; 25 reinterpret_cast<u32*>(base + entry_address.entry_processed_time_offset)};
28 auto entry_count_ptr{ 26 auto entry_count_ptr{
29 reinterpret_cast<u32*>(base + entry_address.header_entry_count_offset)}; 27 reinterpret_cast<u32*>(base + entry_address.header_entry_count_offset)};
30 28
31 *processed_time_ptr = static_cast<u32>( 29 *processed_time_ptr =
32 Core::Timing::CyclesToUs(processor.system->CoreTiming().GetClockTicks() - 30 static_cast<u32>(processor.system->CoreTiming().GetClockTicks() - processor.start_time -
33 processor.start_time - processor.current_processing_time) 31 processor.current_processing_time);
34 .count());
35 (*entry_count_ptr)++; 32 (*entry_count_ptr)++;
36 } 33 }
37} 34}
diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp
index f44fedfd5..9a718a9cc 100644
--- a/src/audio_core/sink/sink_stream.cpp
+++ b/src/audio_core/sink/sink_stream.cpp
@@ -15,7 +15,6 @@
15#include "common/settings.h" 15#include "common/settings.h"
16#include "core/core.h" 16#include "core/core.h"
17#include "core/core_timing.h" 17#include "core/core_timing.h"
18#include "core/core_timing_util.h"
19 18
20namespace AudioCore::Sink { 19namespace AudioCore::Sink {
21 20
diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h
index a73e6e644..56c18ca25 100644
--- a/src/common/wall_clock.h
+++ b/src/common/wall_clock.h
@@ -38,6 +38,22 @@ public:
38 /// @returns Whether the clock directly uses the host's hardware clock. 38 /// @returns Whether the clock directly uses the host's hardware clock.
39 virtual bool IsNative() const = 0; 39 virtual bool IsNative() const = 0;
40 40
41 static inline u64 NSToCNTPCT(u64 ns) {
42 return ns * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den;
43 }
44
45 static inline u64 USToCNTPCT(u64 us) {
46 return us * UsToCNTPCTRatio::num / UsToCNTPCTRatio::den;
47 }
48
49 static inline u64 CNTPCTToNS(u64 cntpct) {
50 return cntpct * NsToCNTPCTRatio::den / NsToCNTPCTRatio::num;
51 }
52
53 static inline u64 CNTPCTToUS(u64 cntpct) {
54 return cntpct * UsToCNTPCTRatio::den / UsToCNTPCTRatio::num;
55 }
56
41protected: 57protected:
42 using NsRatio = std::nano; 58 using NsRatio = std::nano;
43 using UsRatio = std::micro; 59 using UsRatio = std::micro;
@@ -46,6 +62,7 @@ protected:
46 using NsToUsRatio = std::ratio_divide<std::nano, std::micro>; 62 using NsToUsRatio = std::ratio_divide<std::nano, std::micro>;
47 using NsToMsRatio = std::ratio_divide<std::nano, std::milli>; 63 using NsToMsRatio = std::ratio_divide<std::nano, std::milli>;
48 using NsToCNTPCTRatio = std::ratio<CNTFRQ, std::nano::den>; 64 using NsToCNTPCTRatio = std::ratio<CNTFRQ, std::nano::den>;
65 using UsToCNTPCTRatio = std::ratio<CNTFRQ, std::micro::den>;
49}; 66};
50 67
51std::unique_ptr<WallClock> CreateOptimalClock(); 68std::unique_ptr<WallClock> CreateOptimalClock();
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 99602699a..3df4094a7 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -16,7 +16,6 @@ add_library(core STATIC
16 core.h 16 core.h
17 core_timing.cpp 17 core_timing.cpp
18 core_timing.h 18 core_timing.h
19 core_timing_util.h
20 cpu_manager.cpp 19 cpu_manager.cpp
21 cpu_manager.h 20 cpu_manager.h
22 crypto/aes_util.cpp 21 crypto/aes_util.cpp
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 4f2692b05..9a1d5a69a 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -16,7 +16,6 @@
16 16
17#include "common/microprofile.h" 17#include "common/microprofile.h"
18#include "core/core_timing.h" 18#include "core/core_timing.h"
19#include "core/core_timing_util.h"
20#include "core/hardware_properties.h" 19#include "core/hardware_properties.h"
21 20
22namespace Core::Timing { 21namespace Core::Timing {
@@ -45,9 +44,7 @@ struct CoreTiming::Event {
45 } 44 }
46}; 45};
47 46
48CoreTiming::CoreTiming() 47CoreTiming::CoreTiming() : clock{Common::CreateOptimalClock()} {}
49 : cpu_clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)},
50 event_clock{Common::CreateStandardWallClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {}
51 48
52CoreTiming::~CoreTiming() { 49CoreTiming::~CoreTiming() {
53 Reset(); 50 Reset();
@@ -180,7 +177,7 @@ void CoreTiming::AddTicks(u64 ticks_to_add) {
180void CoreTiming::Idle() { 177void CoreTiming::Idle() {
181 if (!event_queue.empty()) { 178 if (!event_queue.empty()) {
182 const u64 next_event_time = event_queue.front().time; 179 const u64 next_event_time = event_queue.front().time;
183 const u64 next_ticks = nsToCycles(std::chrono::nanoseconds(next_event_time)) + 10U; 180 const u64 next_ticks = Common::WallClock::NSToCNTPCT(next_event_time) + 10U;
184 if (next_ticks > ticks) { 181 if (next_ticks > ticks) {
185 ticks = next_ticks; 182 ticks = next_ticks;
186 } 183 }
@@ -193,18 +190,11 @@ void CoreTiming::ResetTicks() {
193 downcount = MAX_SLICE_LENGTH; 190 downcount = MAX_SLICE_LENGTH;
194} 191}
195 192
196u64 CoreTiming::GetCPUTicks() const {
197 if (is_multicore) [[likely]] {
198 return cpu_clock->GetCPUCycles();
199 }
200 return ticks;
201}
202
203u64 CoreTiming::GetClockTicks() const { 193u64 CoreTiming::GetClockTicks() const {
204 if (is_multicore) [[likely]] { 194 if (is_multicore) [[likely]] {
205 return cpu_clock->GetClockCycles(); 195 return clock->GetCNTPCT();
206 } 196 }
207 return CpuCyclesToClockCycles(ticks); 197 return ticks;
208} 198}
209 199
210std::optional<s64> CoreTiming::Advance() { 200std::optional<s64> CoreTiming::Advance() {
@@ -297,9 +287,7 @@ void CoreTiming::ThreadLoop() {
297 } 287 }
298 288
299 paused_set = true; 289 paused_set = true;
300 event_clock->Pause(true);
301 pause_event.Wait(); 290 pause_event.Wait();
302 event_clock->Pause(false);
303 } 291 }
304} 292}
305 293
@@ -315,25 +303,18 @@ void CoreTiming::Reset() {
315 has_started = false; 303 has_started = false;
316} 304}
317 305
318std::chrono::nanoseconds CoreTiming::GetCPUTimeNs() const {
319 if (is_multicore) [[likely]] {
320 return cpu_clock->GetTimeNS();
321 }
322 return CyclesToNs(ticks);
323}
324
325std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { 306std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const {
326 if (is_multicore) [[likely]] { 307 if (is_multicore) [[likely]] {
327 return event_clock->GetTimeNS(); 308 return clock->GetTimeNS();
328 } 309 }
329 return CyclesToNs(ticks); 310 return std::chrono::nanoseconds{Common::WallClock::CNTPCTToNS(ticks)};
330} 311}
331 312
332std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { 313std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
333 if (is_multicore) [[likely]] { 314 if (is_multicore) [[likely]] {
334 return event_clock->GetTimeUS(); 315 return clock->GetTimeUS();
335 } 316 }
336 return CyclesToUs(ticks); 317 return std::chrono::microseconds{Common::WallClock::CNTPCTToUS(ticks)};
337} 318}
338 319
339} // namespace Core::Timing 320} // namespace Core::Timing
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index e7c4a949f..fdacdd94a 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -116,15 +116,9 @@ public:
116 return downcount; 116 return downcount;
117 } 117 }
118 118
119 /// Returns current time in emulated CPU cycles 119 /// Returns the current CNTPCT tick value.
120 u64 GetCPUTicks() const;
121
122 /// Returns current time in emulated in Clock cycles
123 u64 GetClockTicks() const; 120 u64 GetClockTicks() const;
124 121
125 /// Returns current time in nanoseconds.
126 std::chrono::nanoseconds GetCPUTimeNs() const;
127
128 /// Returns current time in microseconds. 122 /// Returns current time in microseconds.
129 std::chrono::microseconds GetGlobalTimeUs() const; 123 std::chrono::microseconds GetGlobalTimeUs() const;
130 124
@@ -142,8 +136,7 @@ private:
142 136
143 void Reset(); 137 void Reset();
144 138
145 std::unique_ptr<Common::WallClock> cpu_clock; 139 std::unique_ptr<Common::WallClock> clock;
146 std::unique_ptr<Common::WallClock> event_clock;
147 140
148 s64 global_timer = 0; 141 s64 global_timer = 0;
149 142
diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h
deleted file mode 100644
index fe5aaefc7..000000000
--- a/src/core/core_timing_util.h
+++ /dev/null
@@ -1,58 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 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#include "core/hardware_properties.h"
10
11namespace Core::Timing {
12
13namespace detail {
14constexpr u64 CNTFREQ_ADJUSTED = Hardware::CNTFREQ / 1000;
15constexpr u64 BASE_CLOCK_RATE_ADJUSTED = Hardware::BASE_CLOCK_RATE / 1000;
16} // namespace detail
17
18[[nodiscard]] constexpr s64 msToCycles(std::chrono::milliseconds ms) {
19 return ms.count() * detail::BASE_CLOCK_RATE_ADJUSTED;
20}
21
22[[nodiscard]] constexpr s64 usToCycles(std::chrono::microseconds us) {
23 return us.count() * detail::BASE_CLOCK_RATE_ADJUSTED / 1000;
24}
25
26[[nodiscard]] constexpr s64 nsToCycles(std::chrono::nanoseconds ns) {
27 return ns.count() * detail::BASE_CLOCK_RATE_ADJUSTED / 1000000;
28}
29
30[[nodiscard]] constexpr u64 msToClockCycles(std::chrono::milliseconds ms) {
31 return static_cast<u64>(ms.count()) * detail::CNTFREQ_ADJUSTED;
32}
33
34[[nodiscard]] constexpr u64 usToClockCycles(std::chrono::microseconds us) {
35 return us.count() * detail::CNTFREQ_ADJUSTED / 1000;
36}
37
38[[nodiscard]] constexpr u64 nsToClockCycles(std::chrono::nanoseconds ns) {
39 return ns.count() * detail::CNTFREQ_ADJUSTED / 1000000;
40}
41
42[[nodiscard]] constexpr u64 CpuCyclesToClockCycles(u64 ticks) {
43 return ticks * detail::CNTFREQ_ADJUSTED / detail::BASE_CLOCK_RATE_ADJUSTED;
44}
45
46[[nodiscard]] constexpr std::chrono::milliseconds CyclesToMs(s64 cycles) {
47 return std::chrono::milliseconds(cycles / detail::BASE_CLOCK_RATE_ADJUSTED);
48}
49
50[[nodiscard]] constexpr std::chrono::nanoseconds CyclesToNs(s64 cycles) {
51 return std::chrono::nanoseconds(cycles * 1000000 / detail::BASE_CLOCK_RATE_ADJUSTED);
52}
53
54[[nodiscard]] constexpr std::chrono::microseconds CyclesToUs(s64 cycles) {
55 return std::chrono::microseconds(cycles * 1000 / detail::BASE_CLOCK_RATE_ADJUSTED);
56}
57
58} // namespace Core::Timing
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index faa12b4f0..75ce5a23c 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -184,7 +184,8 @@ u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
184 prev_highest_thread != highest_thread) [[likely]] { 184 prev_highest_thread != highest_thread) [[likely]] {
185 if (prev_highest_thread != nullptr) [[likely]] { 185 if (prev_highest_thread != nullptr) [[likely]] {
186 IncrementScheduledCount(prev_highest_thread); 186 IncrementScheduledCount(prev_highest_thread);
187 prev_highest_thread->SetLastScheduledTick(m_kernel.System().CoreTiming().GetCPUTicks()); 187 prev_highest_thread->SetLastScheduledTick(
188 m_kernel.System().CoreTiming().GetClockTicks());
188 } 189 }
189 if (m_state.should_count_idle) { 190 if (m_state.should_count_idle) {
190 if (highest_thread != nullptr) [[likely]] { 191 if (highest_thread != nullptr) [[likely]] {
@@ -351,7 +352,7 @@ void KScheduler::SwitchThread(KThread* next_thread) {
351 352
352 // Update the CPU time tracking variables. 353 // Update the CPU time tracking variables.
353 const s64 prev_tick = m_last_context_switch_time; 354 const s64 prev_tick = m_last_context_switch_time;
354 const s64 cur_tick = m_kernel.System().CoreTiming().GetCPUTicks(); 355 const s64 cur_tick = m_kernel.System().CoreTiming().GetClockTicks();
355 const s64 tick_diff = cur_tick - prev_tick; 356 const s64 tick_diff = cur_tick - prev_tick;
356 cur_thread->AddCpuTime(m_core_id, tick_diff); 357 cur_thread->AddCpuTime(m_core_id, tick_diff);
357 if (cur_process != nullptr) { 358 if (cur_process != nullptr) {
diff --git a/src/core/hle/kernel/svc/svc_info.cpp b/src/core/hle/kernel/svc/svc_info.cpp
index 2b2c878b5..445cdd87b 100644
--- a/src/core/hle/kernel/svc/svc_info.cpp
+++ b/src/core/hle/kernel/svc/svc_info.cpp
@@ -199,9 +199,9 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
199 if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { 199 if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
200 const u64 thread_ticks = current_thread->GetCpuTime(); 200 const u64 thread_ticks = current_thread->GetCpuTime();
201 201
202 out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks); 202 out_ticks = thread_ticks + (core_timing.GetClockTicks() - prev_ctx_ticks);
203 } else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) { 203 } else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) {
204 out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks; 204 out_ticks = core_timing.GetClockTicks() - prev_ctx_ticks;
205 } 205 }
206 206
207 *result = out_ticks; 207 *result = out_ticks;
diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp
index 5604a6fda..80aac221b 100644
--- a/src/core/hle/service/hid/hidbus.cpp
+++ b/src/core/hle/service/hid/hidbus.cpp
@@ -5,7 +5,6 @@
5#include "common/settings.h" 5#include "common/settings.h"
6#include "core/core.h" 6#include "core/core.h"
7#include "core/core_timing.h" 7#include "core/core_timing.h"
8#include "core/core_timing_util.h"
9#include "core/hid/hid_types.h" 8#include "core/hid/hid_types.h"
10#include "core/hle/kernel/k_event.h" 9#include "core/hle/kernel/k_event.h"
11#include "core/hle/kernel/k_readable_event.h" 10#include "core/hle/kernel/k_readable_event.h"
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 456f733cf..70762c51a 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -194,17 +194,17 @@ struct GPU::Impl {
194 194
195 [[nodiscard]] u64 GetTicks() const { 195 [[nodiscard]] u64 GetTicks() const {
196 // This values were reversed engineered by fincs from NVN 196 // This values were reversed engineered by fincs from NVN
197 // The gpu clock is reported in units of 385/625 nanoseconds 197 // The GPU clock is 614.4 MHz
198 constexpr u64 gpu_ticks_num = 384; 198 using NsToGPUTickRatio = std::ratio<614'400'000, std::nano::den>;
199 constexpr u64 gpu_ticks_den = 625; 199 static_assert(NsToGPUTickRatio::num == 384 && NsToGPUTickRatio::den == 625);
200
201 u64 nanoseconds = system.CoreTiming().GetGlobalTimeNs().count();
200 202
201 u64 nanoseconds = system.CoreTiming().GetCPUTimeNs().count();
202 if (Settings::values.use_fast_gpu_time.GetValue()) { 203 if (Settings::values.use_fast_gpu_time.GetValue()) {
203 nanoseconds /= 256; 204 nanoseconds /= 256;
204 } 205 }
205 const u64 nanoseconds_num = nanoseconds / gpu_ticks_den; 206
206 const u64 nanoseconds_rem = nanoseconds % gpu_ticks_den; 207 return nanoseconds * NsToGPUTickRatio::num / NsToGPUTickRatio::den;
207 return nanoseconds_num * gpu_ticks_num + (nanoseconds_rem * gpu_ticks_num) / gpu_ticks_den;
208 } 208 }
209 209
210 [[nodiscard]] bool IsAsync() const { 210 [[nodiscard]] bool IsAsync() const {