diff --git a/src/common/settings.h b/src/common/settings.h index ad7bcd16d7..fe5da4e0dd 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -231,11 +231,16 @@ struct Values { CpuAccuracy::Auto, CpuAccuracy::Paranoid, "cpu_accuracy", Category::Cpu}; - SwitchableSetting cpu_clock_rate{linkage, 1020, - 500, 1785, + SwitchableSetting cpu_clock_rate{linkage, 1, + 1, 6, "cpu_clock_rate", Category::Cpu, Specialization::Scalar}; + SwitchableSetting cpu_clock_strategy{linkage, CpuClockStrategy::Clock, + CpuClockStrategy::None, CpuClockStrategy::Both, + "cpu_clock_strategy", Category::Cpu}; + + SwitchableSetting cpu_debug_mode{linkage, false, "cpu_debug_mode", Category::CpuDebug}; Setting cpuopt_page_tables{linkage, true, "cpuopt_page_tables", Category::CpuDebug}; diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index 6e247e9306..03cf1d40c2 100644 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -134,6 +134,8 @@ ENUM(CpuBackend, Dynarmic, Nce); ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid); +ENUM(CpuClockStrategy, None, Clock, Timing, Both) + ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb); ENUM(ConfirmStop, Ask_Always, Ask_Based_On_Game, Ask_Never); diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h index 0d0cd22411..8d06235814 100644 --- a/src/common/wall_clock.h +++ b/src/common/wall_clock.h @@ -8,7 +8,6 @@ #include #include "common/common_types.h" -#include "core/hardware_properties.h" namespace Common { @@ -16,9 +15,7 @@ class WallClock { public: static constexpr u64 CNTFRQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz static constexpr u64 GPUTickFreq = 614'400'000; // GM20B GPU Tick Frequency = 614.4 MHz - static inline u64 CPUTickFreq() { - return Core::Hardware::BASE_CLOCK_RATE(); - } + static constexpr u64 CPUTickFreq = 1'020'000; // CPU Frequency = 1020.0MHz virtual ~WallClock() = default; @@ -54,19 +51,19 @@ public: // Cycle Timing static inline u64 CPUTickToNS(u64 cpu_tick) { - return cpu_tick * CPUTickToNsRatio::num / CPUTickToNsRatio::den(); + return cpu_tick * CPUTickToNsRatio::num / CPUTickToNsRatio::den; } static inline u64 CPUTickToUS(u64 cpu_tick) { - return cpu_tick * CPUTickToUsRatio::num / CPUTickToUsRatio::den(); + return cpu_tick * CPUTickToUsRatio::num / CPUTickToUsRatio::den; } static inline u64 CPUTickToCNTPCT(u64 cpu_tick) { - return cpu_tick * CPUTickToCNTPCTRatio::num / CPUTickToCNTPCTRatio::den(); + return cpu_tick * CPUTickToCNTPCTRatio::num / CPUTickToCNTPCTRatio::den; } static inline u64 CPUTickToGPUTick(u64 cpu_tick) { - return cpu_tick * CPUTickToGPUTickRatio::num / CPUTickToGPUTickRatio::den(); + return cpu_tick * CPUTickToGPUTickRatio::num / CPUTickToGPUTickRatio::den; } protected: @@ -80,34 +77,10 @@ protected: using NsToGPUTickRatio = std::ratio; // Cycle Timing - - struct CPUTickToNsRatio { - static inline std::intmax_t num = std::nano::den; - static inline std::intmax_t den() { - return CPUTickFreq(); - } - }; - - struct CPUTickToUsRatio { - static inline std::intmax_t num = std::micro::den; - static inline std::intmax_t den() { - return CPUTickFreq(); - } - }; - - struct CPUTickToCNTPCTRatio { - static inline std::intmax_t num = CNTFRQ; - static inline std::intmax_t den() { - return CPUTickFreq(); - } - }; - - struct CPUTickToGPUTickRatio { - static inline std::intmax_t num = GPUTickFreq; - static inline std::intmax_t den() { - return CPUTickFreq(); - } - }; + using CPUTickToNsRatio = std::ratio; + using CPUTickToUsRatio = std::ratio; + using CPUTickToCNTPCTRatio = std::ratio; + using CPUTickToGPUTickRatio = std::ratio; }; std::unique_ptr CreateOptimalClock(); diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 1abfa920c4..7c578cccda 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -1,25 +1,28 @@ // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include #include #include #include +#include +#include "common/settings.h" + #ifdef _WIN32 #include "common/windows/timer_resolution.h" #endif #ifdef ARCHITECTURE_x86_64 -#include "common/x64/cpu_wait.h" #endif #include "common/microprofile.h" #include "core/core_timing.h" -#include "core/hardware_properties.h" namespace Core::Timing { +int CoreTiming::rate_multiplier = 1; +int CoreTiming::time_multiplier = 1; + constexpr s64 MAX_SLICE_LENGTH = 10000; std::shared_ptr CreateEvent(std::string name, TimedCallback&& callback) { @@ -185,14 +188,14 @@ void CoreTiming::ResetTicks() { u64 CoreTiming::GetClockTicks() const { if (is_multicore) [[likely]] { - return clock->GetCNTPCT(); + return clock->GetCNTPCT() * rate_multiplier; } return Common::WallClock::CPUTickToCNTPCT(cpu_ticks); } u64 CoreTiming::GetGPUTicks() const { if (is_multicore) [[likely]] { - return clock->GetGPUTick(); + return clock->GetGPUTick() * rate_multiplier; } return Common::WallClock::CPUTickToGPUTick(cpu_ticks); } @@ -302,6 +305,7 @@ void CoreTiming::ThreadLoop() { } void CoreTiming::Reset() { + std::cout << "reset called" << std::endl; paused = true; shutting_down = true; pause_event.Set(); @@ -311,18 +315,27 @@ void CoreTiming::Reset() { } timer_thread.reset(); has_started = false; + + auto clock_strategy = Settings::values.cpu_clock_strategy.GetValue(); + auto multiplier = Settings::values.cpu_clock_rate.GetValue(); + + time_multiplier = (clock_strategy == Settings::CpuClockStrategy::Timing || clock_strategy == Settings::CpuClockStrategy::Both) ? multiplier : 1; + rate_multiplier = (clock_strategy == Settings::CpuClockStrategy::Clock || clock_strategy == Settings::CpuClockStrategy::Both) ? multiplier : 1; + + std::cout << "reset finished " << time_multiplier << " " << rate_multiplier << " " << (int) clock_strategy << " " << multiplier << " " << this << std::endl; } std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { if (is_multicore) [[likely]] { - return clock->GetTimeNS(); + LOG_INFO(Core, "GLOBAL TIME MULTIPLIER {:X}", time_multiplier); + return clock->GetTimeNS() * CoreTiming::time_multiplier; } return std::chrono::nanoseconds{Common::WallClock::CPUTickToNS(cpu_ticks)}; } std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { if (is_multicore) [[likely]] { - return clock->GetTimeUS(); + return clock->GetTimeUS() * time_multiplier; } return std::chrono::microseconds{Common::WallClock::CPUTickToUS(cpu_ticks)}; } diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 7e4dff7f3d..cba1e2af7d 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -15,6 +15,7 @@ #include #include "common/common_types.h" +#include "common/settings_enums.h" #include "common/thread.h" #include "common/wall_clock.h" @@ -178,6 +179,10 @@ private: /// Cycle timing u64 cpu_ticks{}; s64 downcount{}; + + // Clock multipliers + static int rate_multiplier; + static int time_multiplier; }; /// Creates a core timing event with the given name and callback. diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h index 6a2354c3bf..7baea1c073 100644 --- a/src/core/hardware_properties.h +++ b/src/core/hardware_properties.h @@ -5,22 +5,15 @@ #pragma once #include -#include #include "common/bit_util.h" #include "common/common_types.h" -#include "common/settings.h" -#include "common/logging/log.h" namespace Core { namespace Hardware { -inline u64 BASE_CLOCK_RATE() { - LOG_DEBUG(Core, "Settings reported clock rate={:08X}", Settings::values.cpu_clock_rate.GetValue()); - // std::cout << Settings::values.cpu_clock_rate.GetValue() << std::endl; - return Settings::values.cpu_clock_rate.GetValue() * 1'000'000; -} +constexpr u64 BASE_CLOCK_RATE = 1'020'000; // CPU Frequency = 1020.0 MHz constexpr u64 CNTFREQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores diff --git a/src/core/hle/service/apm/apm_controller.cpp b/src/core/hle/service/apm/apm_controller.cpp index 60540df27c..72bbaba3f3 100644 --- a/src/core/hle/service/apm/apm_controller.cpp +++ b/src/core/hle/service/apm/apm_controller.cpp @@ -80,10 +80,6 @@ PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(Performa void Controller::SetClockSpeed(u32 mhz) { LOG_DEBUG(Service_APM, "called, mhz={:08X}", mhz); - - // TODO: needs to be verified - // Settings::values.cpu_clock_rate.SetGlobal(false); - // Settings::values.cpu_clock_rate.SetValue(mhz); } } // namespace Service::APM diff --git a/src/core/hle/service/vi/conductor.cpp b/src/core/hle/service/vi/conductor.cpp index c8ce4fca04..53c1044b50 100644 --- a/src/core/hle/service/vi/conductor.cpp +++ b/src/core/hle/service/vi/conductor.cpp @@ -9,7 +9,7 @@ #include "core/hle/service/vi/display_list.h" #include "core/hle/service/vi/vsync_manager.h" -constexpr auto FrameNs = std::chrono::nanoseconds{1000000000 / 60}; +constexpr auto FrameNs = std::chrono::nanoseconds{1'000'000'000 / 60}; namespace Service::VI { diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp index c82734b0e6..1226c7c01b 100644 --- a/src/yuzu/configuration/configure_cpu.cpp +++ b/src/yuzu/configuration/configure_cpu.cpp @@ -74,7 +74,8 @@ void ConfigureCpu::Setup(const ConfigurationShared::Builder& builder) { } else if (setting->Id() == Settings::values.cpu_backend.Id()) { backend_layout->addWidget(widget); backend_combobox = widget->combobox; - } else if (setting->Id() == Settings::values.cpu_clock_rate.Id()) { + } else if (setting->Id() == Settings::values.cpu_clock_rate.Id() + || setting->Id() == Settings::values.cpu_clock_strategy.Id()) { clock_layout->addWidget(widget); } else { // Presently, all other settings here are unsafe checkboxes diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index f4b8db22bc..87c8ae502a 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -77,8 +77,14 @@ std::unique_ptr InitializeTranslations(QWidget* parent) { tr("This setting controls the accuracy of the emulated CPU.\nDon't change this unless " "you know what you are doing.")); INSERT(Settings, cpu_backend, tr("Backend:"), QStringLiteral()); - INSERT(Settings, cpu_clock_rate, tr("CPU Clock Rate (MHz):"), tr("Increasing CPU clock rate may " + INSERT(Settings, cpu_clock_rate, tr("CPU Clock Multiplier:"), tr("Increasing CPU clock speed may " "improve performance, but may also reduce stability.")); + INSERT(Settings, cpu_clock_strategy, tr("Clock Strategy:"), + tr("Some games use clock rate for timings, others use clock timing, and some even use both.\n" + "Generally, this setting will increase a game's default FPS, but may cause unintended\n" + "speedups or gameplay issues; for this reason, dedicated mods that unlock VSync and\n" + "enable dynamic FPS are preferred over this setting.\nOnly change if you know what you're " + "doing.")); // Cpu Debug @@ -356,6 +362,16 @@ std::unique_ptr ComboboxEnumeration(QWidget* parent) { PAIR(CpuAccuracy, Unsafe, tr("Unsafe")), PAIR(CpuAccuracy, Paranoid, tr("Paranoid (disables most optimizations)")), }}); + + translations->insert( + {Settings::EnumMetadata::Index(), + { + PAIR(CpuClockStrategy, None, tr("None")), + PAIR(CpuClockStrategy, Clock, tr("Clock Rate")), + PAIR(CpuClockStrategy, Timing, tr("Clock Timing")), + PAIR(CpuClockStrategy, Both, tr("Both")), + }}); + translations->insert({Settings::EnumMetadata::Index(), { PAIR(CpuBackend, Dynarmic, tr("Dynarmic")),