Somewhat functional clock timing setting
Some checks failed
eden-build / windows (msvc) (pull_request) Successful in 35m58s
eden-build / source (pull_request) Has been cancelled
eden-build / linux (pull_request) Has been cancelled
eden-build / android (pull_request) Has been cancelled
eden-license / license-header (pull_request_target) Has been cancelled
Some checks failed
eden-build / windows (msvc) (pull_request) Successful in 35m58s
eden-build / source (pull_request) Has been cancelled
eden-build / linux (pull_request) Has been cancelled
eden-build / android (pull_request) Has been cancelled
eden-license / license-header (pull_request_target) Has been cancelled
hangs when clock timing or both is set Signed-off-by: swurl <swurl@swurl.xyz>
This commit is contained in:
parent
449edd5224
commit
ec60d21616
10 changed files with 64 additions and 60 deletions
|
@ -231,11 +231,16 @@ struct Values {
|
||||||
CpuAccuracy::Auto, CpuAccuracy::Paranoid,
|
CpuAccuracy::Auto, CpuAccuracy::Paranoid,
|
||||||
"cpu_accuracy", Category::Cpu};
|
"cpu_accuracy", Category::Cpu};
|
||||||
|
|
||||||
SwitchableSetting<u32, true> cpu_clock_rate{linkage, 1020,
|
SwitchableSetting<u32, true> cpu_clock_rate{linkage, 1,
|
||||||
500, 1785,
|
1, 6,
|
||||||
"cpu_clock_rate", Category::Cpu,
|
"cpu_clock_rate", Category::Cpu,
|
||||||
Specialization::Scalar};
|
Specialization::Scalar};
|
||||||
|
|
||||||
|
SwitchableSetting<CpuClockStrategy, true> cpu_clock_strategy{linkage, CpuClockStrategy::Clock,
|
||||||
|
CpuClockStrategy::None, CpuClockStrategy::Both,
|
||||||
|
"cpu_clock_strategy", Category::Cpu};
|
||||||
|
|
||||||
|
|
||||||
SwitchableSetting<bool> cpu_debug_mode{linkage, false, "cpu_debug_mode", Category::CpuDebug};
|
SwitchableSetting<bool> cpu_debug_mode{linkage, false, "cpu_debug_mode", Category::CpuDebug};
|
||||||
|
|
||||||
Setting<bool> cpuopt_page_tables{linkage, true, "cpuopt_page_tables", Category::CpuDebug};
|
Setting<bool> cpuopt_page_tables{linkage, true, "cpuopt_page_tables", Category::CpuDebug};
|
||||||
|
|
|
@ -134,6 +134,8 @@ ENUM(CpuBackend, Dynarmic, Nce);
|
||||||
|
|
||||||
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid);
|
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid);
|
||||||
|
|
||||||
|
ENUM(CpuClockStrategy, None, Clock, Timing, Both)
|
||||||
|
|
||||||
ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb);
|
ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb);
|
||||||
|
|
||||||
ENUM(ConfirmStop, Ask_Always, Ask_Based_On_Game, Ask_Never);
|
ENUM(ConfirmStop, Ask_Always, Ask_Based_On_Game, Ask_Never);
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#include <ratio>
|
#include <ratio>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hardware_properties.h"
|
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
|
@ -16,9 +15,7 @@ class WallClock {
|
||||||
public:
|
public:
|
||||||
static constexpr u64 CNTFRQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz
|
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 constexpr u64 GPUTickFreq = 614'400'000; // GM20B GPU Tick Frequency = 614.4 MHz
|
||||||
static inline u64 CPUTickFreq() {
|
static constexpr u64 CPUTickFreq = 1'020'000; // CPU Frequency = 1020.0MHz
|
||||||
return Core::Hardware::BASE_CLOCK_RATE();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~WallClock() = default;
|
virtual ~WallClock() = default;
|
||||||
|
|
||||||
|
@ -54,19 +51,19 @@ public:
|
||||||
// Cycle Timing
|
// Cycle Timing
|
||||||
|
|
||||||
static inline u64 CPUTickToNS(u64 cpu_tick) {
|
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) {
|
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) {
|
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) {
|
static inline u64 CPUTickToGPUTick(u64 cpu_tick) {
|
||||||
return cpu_tick * CPUTickToGPUTickRatio::num / CPUTickToGPUTickRatio::den();
|
return cpu_tick * CPUTickToGPUTickRatio::num / CPUTickToGPUTickRatio::den;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -80,34 +77,10 @@ protected:
|
||||||
using NsToGPUTickRatio = std::ratio<GPUTickFreq, std::nano::den>;
|
using NsToGPUTickRatio = std::ratio<GPUTickFreq, std::nano::den>;
|
||||||
|
|
||||||
// Cycle Timing
|
// Cycle Timing
|
||||||
|
using CPUTickToNsRatio = std::ratio<std::nano::den, CPUTickFreq>;
|
||||||
struct CPUTickToNsRatio {
|
using CPUTickToUsRatio = std::ratio<std::micro::den, CPUTickFreq>;
|
||||||
static inline std::intmax_t num = std::nano::den;
|
using CPUTickToCNTPCTRatio = std::ratio<CNTFRQ, CPUTickFreq>;
|
||||||
static inline std::intmax_t den() {
|
using CPUTickToGPUTickRatio = std::ratio<GPUTickFreq, CPUTickFreq>;
|
||||||
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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<WallClock> CreateOptimalClock();
|
std::unique_ptr<WallClock> CreateOptimalClock();
|
||||||
|
|
|
@ -1,25 +1,28 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include "common/settings.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "common/windows/timer_resolution.h"
|
#include "common/windows/timer_resolution.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ARCHITECTURE_x86_64
|
#ifdef ARCHITECTURE_x86_64
|
||||||
#include "common/x64/cpu_wait.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "common/microprofile.h"
|
#include "common/microprofile.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hardware_properties.h"
|
|
||||||
|
|
||||||
namespace Core::Timing {
|
namespace Core::Timing {
|
||||||
|
|
||||||
|
int CoreTiming::rate_multiplier = 1;
|
||||||
|
int CoreTiming::time_multiplier = 1;
|
||||||
|
|
||||||
constexpr s64 MAX_SLICE_LENGTH = 10000;
|
constexpr s64 MAX_SLICE_LENGTH = 10000;
|
||||||
|
|
||||||
std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
|
std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
|
||||||
|
@ -185,14 +188,14 @@ void CoreTiming::ResetTicks() {
|
||||||
|
|
||||||
u64 CoreTiming::GetClockTicks() const {
|
u64 CoreTiming::GetClockTicks() const {
|
||||||
if (is_multicore) [[likely]] {
|
if (is_multicore) [[likely]] {
|
||||||
return clock->GetCNTPCT();
|
return clock->GetCNTPCT() * rate_multiplier;
|
||||||
}
|
}
|
||||||
return Common::WallClock::CPUTickToCNTPCT(cpu_ticks);
|
return Common::WallClock::CPUTickToCNTPCT(cpu_ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 CoreTiming::GetGPUTicks() const {
|
u64 CoreTiming::GetGPUTicks() const {
|
||||||
if (is_multicore) [[likely]] {
|
if (is_multicore) [[likely]] {
|
||||||
return clock->GetGPUTick();
|
return clock->GetGPUTick() * rate_multiplier;
|
||||||
}
|
}
|
||||||
return Common::WallClock::CPUTickToGPUTick(cpu_ticks);
|
return Common::WallClock::CPUTickToGPUTick(cpu_ticks);
|
||||||
}
|
}
|
||||||
|
@ -302,6 +305,7 @@ void CoreTiming::ThreadLoop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreTiming::Reset() {
|
void CoreTiming::Reset() {
|
||||||
|
std::cout << "reset called" << std::endl;
|
||||||
paused = true;
|
paused = true;
|
||||||
shutting_down = true;
|
shutting_down = true;
|
||||||
pause_event.Set();
|
pause_event.Set();
|
||||||
|
@ -311,18 +315,27 @@ void CoreTiming::Reset() {
|
||||||
}
|
}
|
||||||
timer_thread.reset();
|
timer_thread.reset();
|
||||||
has_started = false;
|
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 {
|
std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const {
|
||||||
if (is_multicore) [[likely]] {
|
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)};
|
return std::chrono::nanoseconds{Common::WallClock::CPUTickToNS(cpu_ticks)};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
|
std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
|
||||||
if (is_multicore) [[likely]] {
|
if (is_multicore) [[likely]] {
|
||||||
return clock->GetTimeUS();
|
return clock->GetTimeUS() * time_multiplier;
|
||||||
}
|
}
|
||||||
return std::chrono::microseconds{Common::WallClock::CPUTickToUS(cpu_ticks)};
|
return std::chrono::microseconds{Common::WallClock::CPUTickToUS(cpu_ticks)};
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <boost/heap/fibonacci_heap.hpp>
|
#include <boost/heap/fibonacci_heap.hpp>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/settings_enums.h"
|
||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
#include "common/wall_clock.h"
|
#include "common/wall_clock.h"
|
||||||
|
|
||||||
|
@ -178,6 +179,10 @@ private:
|
||||||
/// Cycle timing
|
/// Cycle timing
|
||||||
u64 cpu_ticks{};
|
u64 cpu_ticks{};
|
||||||
s64 downcount{};
|
s64 downcount{};
|
||||||
|
|
||||||
|
// Clock multipliers
|
||||||
|
static int rate_multiplier;
|
||||||
|
static int time_multiplier;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Creates a core timing event with the given name and callback.
|
/// Creates a core timing event with the given name and callback.
|
||||||
|
|
|
@ -5,22 +5,15 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "common/bit_util.h"
|
#include "common/bit_util.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/settings.h"
|
|
||||||
#include "common/logging/log.h"
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
namespace Hardware {
|
namespace Hardware {
|
||||||
|
|
||||||
inline u64 BASE_CLOCK_RATE() {
|
constexpr u64 BASE_CLOCK_RATE = 1'020'000; // CPU Frequency = 1020.0 MHz
|
||||||
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 CNTFREQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz
|
constexpr u64 CNTFREQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz
|
||||||
constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores
|
constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores
|
||||||
|
|
||||||
|
|
|
@ -80,10 +80,6 @@ PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(Performa
|
||||||
|
|
||||||
void Controller::SetClockSpeed(u32 mhz) {
|
void Controller::SetClockSpeed(u32 mhz) {
|
||||||
LOG_DEBUG(Service_APM, "called, mhz={:08X}", 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
|
} // namespace Service::APM
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "core/hle/service/vi/display_list.h"
|
#include "core/hle/service/vi/display_list.h"
|
||||||
#include "core/hle/service/vi/vsync_manager.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 {
|
namespace Service::VI {
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,8 @@ void ConfigureCpu::Setup(const ConfigurationShared::Builder& builder) {
|
||||||
} else if (setting->Id() == Settings::values.cpu_backend.Id()) {
|
} else if (setting->Id() == Settings::values.cpu_backend.Id()) {
|
||||||
backend_layout->addWidget(widget);
|
backend_layout->addWidget(widget);
|
||||||
backend_combobox = widget->combobox;
|
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);
|
clock_layout->addWidget(widget);
|
||||||
} else {
|
} else {
|
||||||
// Presently, all other settings here are unsafe checkboxes
|
// Presently, all other settings here are unsafe checkboxes
|
||||||
|
|
|
@ -77,8 +77,14 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
|
||||||
tr("This setting controls the accuracy of the emulated CPU.\nDon't change this unless "
|
tr("This setting controls the accuracy of the emulated CPU.\nDon't change this unless "
|
||||||
"you know what you are doing."));
|
"you know what you are doing."));
|
||||||
INSERT(Settings, cpu_backend, tr("Backend:"), QStringLiteral());
|
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."));
|
"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
|
// Cpu Debug
|
||||||
|
|
||||||
|
@ -356,6 +362,16 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
|
||||||
PAIR(CpuAccuracy, Unsafe, tr("Unsafe")),
|
PAIR(CpuAccuracy, Unsafe, tr("Unsafe")),
|
||||||
PAIR(CpuAccuracy, Paranoid, tr("Paranoid (disables most optimizations)")),
|
PAIR(CpuAccuracy, Paranoid, tr("Paranoid (disables most optimizations)")),
|
||||||
}});
|
}});
|
||||||
|
|
||||||
|
translations->insert(
|
||||||
|
{Settings::EnumMetadata<Settings::CpuClockStrategy>::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<Settings::CpuBackend>::Index(),
|
translations->insert({Settings::EnumMetadata<Settings::CpuBackend>::Index(),
|
||||||
{
|
{
|
||||||
PAIR(CpuBackend, Dynarmic, tr("Dynarmic")),
|
PAIR(CpuBackend, Dynarmic, tr("Dynarmic")),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue