general: remove references to single core mode
This commit is contained in:
@@ -44,7 +44,6 @@ void LogSettings() {
|
||||
log_setting("System_LanguageIndex", values.language_index.GetValue());
|
||||
log_setting("System_RegionIndex", values.region_index.GetValue());
|
||||
log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
|
||||
log_setting("Core_UseMultiCore", values.use_multi_core.GetValue());
|
||||
log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue());
|
||||
log_setting("Renderer_UseResolutionScaling", values.resolution_setup.GetValue());
|
||||
log_setting("Renderer_ScalingFilter", values.scaling_filter.GetValue());
|
||||
@@ -166,7 +165,6 @@ void RestoreGlobalState(bool is_powered_on) {
|
||||
values.volume.SetGlobal(true);
|
||||
|
||||
// Core
|
||||
values.use_multi_core.SetGlobal(true);
|
||||
values.use_extended_memory_layout.SetGlobal(true);
|
||||
|
||||
// CPU
|
||||
|
||||
@@ -465,7 +465,6 @@ struct Values {
|
||||
RangedSetting<u8> volume{100, 0, 100, "volume"};
|
||||
|
||||
// Core
|
||||
Setting<bool> use_multi_core{true, "use_multi_core"};
|
||||
Setting<bool> use_extended_memory_layout{false, "use_extended_memory_layout"};
|
||||
|
||||
// Cpu
|
||||
|
||||
@@ -37,10 +37,8 @@ public:
|
||||
YUZU_NON_COPYABLE(ARM_Interface);
|
||||
YUZU_NON_MOVEABLE(ARM_Interface);
|
||||
|
||||
explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers_,
|
||||
bool uses_wall_clock_)
|
||||
: system{system_}, interrupt_handlers{interrupt_handlers_}, uses_wall_clock{
|
||||
uses_wall_clock_} {}
|
||||
explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers_)
|
||||
: system{system_}, interrupt_handlers{interrupt_handlers_}, uses_wall_clock{true} {}
|
||||
virtual ~ARM_Interface() = default;
|
||||
|
||||
struct ThreadContext32 {
|
||||
|
||||
@@ -125,26 +125,11 @@ public:
|
||||
}
|
||||
|
||||
void AddTicks(u64 ticks) override {
|
||||
ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
|
||||
|
||||
// Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
|
||||
// rough approximation of the amount of executed ticks in the system, it may be thrown off
|
||||
// if not all cores are doing a similar amount of work. Instead of doing this, we should
|
||||
// device a way so that timing is consistent across all cores without increasing the ticks 4
|
||||
// times.
|
||||
u64 amortized_ticks =
|
||||
(ticks - num_interpreted_instructions) / Core::Hardware::NUM_CPU_CORES;
|
||||
// Always execute at least one tick.
|
||||
amortized_ticks = std::max<u64>(amortized_ticks, 1);
|
||||
|
||||
parent.system.CoreTiming().AddTicks(amortized_ticks);
|
||||
num_interpreted_instructions = 0;
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
u64 GetTicksRemaining() override {
|
||||
ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
|
||||
|
||||
return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) {
|
||||
@@ -172,7 +157,6 @@ public:
|
||||
Core::Memory::Memory& memory;
|
||||
std::size_t num_interpreted_instructions{};
|
||||
bool debugger_enabled{};
|
||||
static constexpr u64 minimum_run_cycles = 1000U;
|
||||
};
|
||||
|
||||
std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* page_table) const {
|
||||
@@ -314,10 +298,8 @@ void ARM_Dynarmic_32::RewindBreakpointInstruction() {
|
||||
}
|
||||
|
||||
ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_,
|
||||
bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
|
||||
std::size_t core_index_)
|
||||
: ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
|
||||
cb(std::make_unique<DynarmicCallbacks32>(*this)),
|
||||
ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_)
|
||||
: ARM_Interface{system_, interrupt_handlers_}, cb(std::make_unique<DynarmicCallbacks32>(*this)),
|
||||
cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index_},
|
||||
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
|
||||
null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {}
|
||||
|
||||
@@ -28,7 +28,7 @@ class System;
|
||||
|
||||
class ARM_Dynarmic_32 final : public ARM_Interface {
|
||||
public:
|
||||
ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_,
|
||||
ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_,
|
||||
ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
|
||||
~ARM_Dynarmic_32() override;
|
||||
|
||||
|
||||
@@ -166,24 +166,11 @@ public:
|
||||
}
|
||||
|
||||
void AddTicks(u64 ticks) override {
|
||||
ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
|
||||
|
||||
// Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
|
||||
// rough approximation of the amount of executed ticks in the system, it may be thrown off
|
||||
// if not all cores are doing a similar amount of work. Instead of doing this, we should
|
||||
// device a way so that timing is consistent across all cores without increasing the ticks 4
|
||||
// times.
|
||||
u64 amortized_ticks = ticks / Core::Hardware::NUM_CPU_CORES;
|
||||
// Always execute at least one tick.
|
||||
amortized_ticks = std::max<u64>(amortized_ticks, 1);
|
||||
|
||||
parent.system.CoreTiming().AddTicks(amortized_ticks);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
u64 GetTicksRemaining() override {
|
||||
ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
|
||||
|
||||
return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
u64 GetCNTPCT() override {
|
||||
@@ -216,7 +203,6 @@ public:
|
||||
u64 tpidrro_el0 = 0;
|
||||
u64 tpidr_el0 = 0;
|
||||
bool debugger_enabled{};
|
||||
static constexpr u64 minimum_run_cycles = 1000U;
|
||||
};
|
||||
|
||||
std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* page_table,
|
||||
@@ -374,9 +360,8 @@ void ARM_Dynarmic_64::RewindBreakpointInstruction() {
|
||||
}
|
||||
|
||||
ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_,
|
||||
bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
|
||||
std::size_t core_index_)
|
||||
: ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
|
||||
ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_)
|
||||
: ARM_Interface{system_, interrupt_handlers_},
|
||||
cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_},
|
||||
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
|
||||
null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {}
|
||||
|
||||
@@ -26,7 +26,7 @@ class System;
|
||||
|
||||
class ARM_Dynarmic_64 final : public ARM_Interface {
|
||||
public:
|
||||
ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_,
|
||||
ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_,
|
||||
ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
|
||||
~ARM_Dynarmic_64() override;
|
||||
|
||||
|
||||
@@ -177,14 +177,8 @@ struct System::Impl {
|
||||
|
||||
device_memory = std::make_unique<Core::DeviceMemory>();
|
||||
|
||||
is_multicore = Settings::values.use_multi_core.GetValue();
|
||||
is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue();
|
||||
|
||||
kernel.SetMulticore(is_multicore);
|
||||
cpu_manager.SetMulticore(is_multicore);
|
||||
cpu_manager.SetAsyncGpu(is_async_gpu);
|
||||
core_timing.SetMulticore(is_multicore);
|
||||
|
||||
kernel.Initialize();
|
||||
cpu_manager.Initialize();
|
||||
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
|
||||
@@ -449,7 +443,6 @@ struct System::Impl {
|
||||
std::unique_ptr<Core::PerfStats> perf_stats;
|
||||
Core::SpeedLimiter speed_limiter;
|
||||
|
||||
bool is_multicore{};
|
||||
bool is_async_gpu{};
|
||||
|
||||
ExecuteProgramCallback execute_program_callback;
|
||||
@@ -818,10 +811,6 @@ void System::ExitDynarmicProfile() {
|
||||
MicroProfileLeave(impl->microprofile_dynarmic[core], impl->dynarmic_ticks[core]);
|
||||
}
|
||||
|
||||
bool System::IsMulticore() const {
|
||||
return impl->is_multicore;
|
||||
}
|
||||
|
||||
bool System::DebuggerEnabled() const {
|
||||
return Settings::values.use_gdbstub.GetValue();
|
||||
}
|
||||
|
||||
@@ -378,9 +378,6 @@ public:
|
||||
/// Exit Dynarmic Microprofile
|
||||
void ExitDynarmicProfile();
|
||||
|
||||
/// Tells if system is running on multicore.
|
||||
[[nodiscard]] bool IsMulticore() const;
|
||||
|
||||
/// Tells if the system debugger is enabled.
|
||||
[[nodiscard]] bool DebuggerEnabled() const;
|
||||
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
|
||||
namespace Core::Timing {
|
||||
|
||||
constexpr s64 MAX_SLICE_LENGTH = 4000;
|
||||
|
||||
std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
|
||||
return std::make_shared<EventType>(std::move(callback), std::move(name));
|
||||
}
|
||||
@@ -57,10 +55,9 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
|
||||
on_thread_init = std::move(on_thread_init_);
|
||||
event_fifo_id = 0;
|
||||
shutting_down = false;
|
||||
ticks = 0;
|
||||
const auto empty_timed_callback = [](std::uintptr_t, std::chrono::nanoseconds) {};
|
||||
ev_lost = CreateEvent("_lost_event", empty_timed_callback);
|
||||
if (is_multicore) {
|
||||
|
||||
const auto hardware_concurrency = std::thread::hardware_concurrency();
|
||||
size_t id = 0;
|
||||
worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++);
|
||||
@@ -68,7 +65,6 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
|
||||
worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CoreTiming::Shutdown() {
|
||||
is_paused = true;
|
||||
@@ -90,13 +86,13 @@ void CoreTiming::Pause(bool is_paused_) {
|
||||
if (is_paused_ == paused_state.load(std::memory_order_relaxed)) {
|
||||
return;
|
||||
}
|
||||
if (is_multicore) {
|
||||
|
||||
is_paused = is_paused_;
|
||||
event_cv.notify_all();
|
||||
if (!is_paused_) {
|
||||
wait_pause_cv.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
paused_state.store(is_paused_, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
@@ -106,22 +102,20 @@ void CoreTiming::SyncPause(bool is_paused_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_multicore) {
|
||||
is_paused = is_paused_;
|
||||
event_cv.notify_all();
|
||||
if (!is_paused_) {
|
||||
wait_pause_cv.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
paused_state.store(is_paused_, std::memory_order_relaxed);
|
||||
if (is_multicore) {
|
||||
|
||||
if (is_paused_) {
|
||||
wait_signal_cv.wait(main_lock, [this] { return pause_count == worker_threads.size(); });
|
||||
} else {
|
||||
wait_signal_cv.wait(main_lock, [this] { return pause_count == 0; });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CoreTiming::IsRunning() const {
|
||||
return !paused_state.load(std::memory_order_acquire);
|
||||
@@ -144,10 +138,8 @@ void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
|
||||
|
||||
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
|
||||
|
||||
if (is_multicore) {
|
||||
event_cv.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
||||
std::uintptr_t user_data) {
|
||||
@@ -164,40 +156,13 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
||||
}
|
||||
}
|
||||
|
||||
void CoreTiming::AddTicks(u64 ticks_to_add) {
|
||||
ticks += ticks_to_add;
|
||||
downcount -= static_cast<s64>(ticks);
|
||||
}
|
||||
|
||||
void CoreTiming::Idle() {
|
||||
if (!event_queue.empty()) {
|
||||
const u64 next_event_time = event_queue.front().time;
|
||||
const u64 next_ticks = nsToCycles(std::chrono::nanoseconds(next_event_time)) + 10U;
|
||||
if (next_ticks > ticks) {
|
||||
ticks = next_ticks;
|
||||
}
|
||||
return;
|
||||
}
|
||||
ticks += 1000U;
|
||||
}
|
||||
|
||||
void CoreTiming::ResetTicks() {
|
||||
downcount = MAX_SLICE_LENGTH;
|
||||
}
|
||||
|
||||
u64 CoreTiming::GetCPUTicks() const {
|
||||
if (is_multicore) {
|
||||
return clock->GetCPUCycles();
|
||||
}
|
||||
return ticks;
|
||||
}
|
||||
|
||||
u64 CoreTiming::GetClockTicks() const {
|
||||
if (is_multicore) {
|
||||
return clock->GetClockCycles();
|
||||
}
|
||||
return CpuCyclesToClockCycles(ticks);
|
||||
}
|
||||
|
||||
void CoreTiming::ClearPendingEvents() {
|
||||
std::unique_lock main_lock(event_mutex);
|
||||
@@ -285,17 +250,11 @@ void CoreTiming::ThreadLoop() {
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const {
|
||||
if (is_multicore) {
|
||||
return clock->GetTimeNS();
|
||||
}
|
||||
return CyclesToNs(ticks);
|
||||
}
|
||||
|
||||
std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
|
||||
if (is_multicore) {
|
||||
return clock->GetTimeUS();
|
||||
}
|
||||
return CyclesToUs(ticks);
|
||||
}
|
||||
|
||||
} // namespace Core::Timing
|
||||
|
||||
@@ -65,16 +65,6 @@ public:
|
||||
/// Tears down all timing related functionality.
|
||||
void Shutdown();
|
||||
|
||||
/// Sets if emulation is multicore or single core, must be set before Initialize
|
||||
void SetMulticore(bool is_multicore_) {
|
||||
is_multicore = is_multicore_;
|
||||
}
|
||||
|
||||
/// Check if it's using host timing.
|
||||
bool IsHostTiming() const {
|
||||
return is_multicore;
|
||||
}
|
||||
|
||||
/// Pauses/Unpauses the execution of the timer thread.
|
||||
void Pause(bool is_paused);
|
||||
|
||||
@@ -101,16 +91,6 @@ public:
|
||||
/// We only permit one event of each type in the queue at a time.
|
||||
void RemoveEvent(const std::shared_ptr<EventType>& event_type);
|
||||
|
||||
void AddTicks(u64 ticks_to_add);
|
||||
|
||||
void ResetTicks();
|
||||
|
||||
void Idle();
|
||||
|
||||
s64 GetDowncount() const {
|
||||
return downcount;
|
||||
}
|
||||
|
||||
/// Returns current time in emulated CPU cycles
|
||||
u64 GetCPUTicks() const;
|
||||
|
||||
@@ -123,9 +103,6 @@ public:
|
||||
/// Returns current time in nanoseconds.
|
||||
std::chrono::nanoseconds GetGlobalTimeNs() const;
|
||||
|
||||
/// Checks for events manually and returns time in nanoseconds for next event, threadsafe.
|
||||
std::optional<s64> Advance();
|
||||
|
||||
private:
|
||||
struct Event;
|
||||
|
||||
@@ -135,6 +112,9 @@ private:
|
||||
static void ThreadEntry(CoreTiming& instance, size_t id);
|
||||
void ThreadLoop();
|
||||
|
||||
/// Checks for events manually and returns time in nanoseconds for next event, threadsafe.
|
||||
std::optional<s64> Advance();
|
||||
|
||||
std::unique_ptr<Common::WallClock> clock;
|
||||
|
||||
u64 global_timer = 0;
|
||||
@@ -162,12 +142,7 @@ private:
|
||||
std::atomic<bool> paused_state{};
|
||||
bool is_paused{};
|
||||
bool shutting_down{};
|
||||
bool is_multicore{};
|
||||
size_t pause_count{};
|
||||
|
||||
/// Cycle timing
|
||||
u64 ticks{};
|
||||
s64 downcount{};
|
||||
};
|
||||
|
||||
/// Creates a core timing event with the given name and callback.
|
||||
|
||||
@@ -26,7 +26,7 @@ void CpuManager::ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager
|
||||
}
|
||||
|
||||
void CpuManager::Initialize() {
|
||||
num_cores = is_multicore ? Core::Hardware::NUM_CPU_CORES : 1;
|
||||
const auto num_cores{Core::Hardware::NUM_CPU_CORES};
|
||||
gpu_barrier = std::make_unique<Common::Barrier>(num_cores + 1);
|
||||
|
||||
for (std::size_t core = 0; core < num_cores; core++) {
|
||||
@@ -35,33 +35,13 @@ void CpuManager::Initialize() {
|
||||
}
|
||||
|
||||
void CpuManager::Shutdown() {
|
||||
for (std::size_t core = 0; core < num_cores; core++) {
|
||||
for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
|
||||
if (core_data[core].host_thread.joinable()) {
|
||||
core_data[core].host_thread.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::GuestActivateFunction() {
|
||||
if (is_multicore) {
|
||||
MultiCoreGuestActivate();
|
||||
} else {
|
||||
SingleCoreGuestActivate();
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::GuestThreadFunction() {
|
||||
if (is_multicore) {
|
||||
MultiCoreRunGuestThread();
|
||||
} else {
|
||||
SingleCoreRunGuestThread();
|
||||
}
|
||||
}
|
||||
|
||||
void CpuManager::ShutdownThreadFunction() {
|
||||
ShutdownThread();
|
||||
}
|
||||
|
||||
void CpuManager::WaitForAndHandleInterrupt() {
|
||||
auto& kernel = system.Kernel();
|
||||
auto& physical_core = kernel.CurrentPhysicalCore();
|
||||
@@ -82,30 +62,21 @@ void CpuManager::HandleInterrupt() {
|
||||
Kernel::KInterruptManager::HandleInterrupt(kernel, static_cast<s32>(core_index));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// MultiCore ///
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CpuManager::MultiCoreGuestActivate() {
|
||||
void CpuManager::GuestActivate() {
|
||||
// Similar to the HorizonKernelMain callback in HOS
|
||||
auto& kernel = system.Kernel();
|
||||
auto* scheduler = kernel.CurrentScheduler();
|
||||
|
||||
kernel.SetCurrentEmuThread(scheduler->GetSchedulerCurrentThread());
|
||||
scheduler->Activate();
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void CpuManager::MultiCoreRunGuestThread() {
|
||||
void CpuManager::RunGuestThread() {
|
||||
// Similar to UserModeThreadStarter in HOS
|
||||
auto& kernel = system.Kernel();
|
||||
auto* thread = kernel.GetCurrentEmuThread();
|
||||
thread->EnableDispatch();
|
||||
|
||||
MultiCoreRunGuestLoop();
|
||||
}
|
||||
|
||||
void CpuManager::MultiCoreRunGuestLoop() {
|
||||
auto& kernel = system.Kernel();
|
||||
kernel.GetCurrentEmuThread()->EnableDispatch();
|
||||
|
||||
while (true) {
|
||||
auto* physical_core = &kernel.CurrentPhysicalCore();
|
||||
@@ -116,24 +87,14 @@ void CpuManager::MultiCoreRunGuestLoop() {
|
||||
|
||||
HandleInterrupt();
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// SingleCore ///
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CpuManager::SingleCoreGuestActivate() {}
|
||||
|
||||
void CpuManager::SingleCoreRunGuestThread() {}
|
||||
|
||||
void CpuManager::SingleCoreRunGuestLoop() {}
|
||||
|
||||
void CpuManager::PreemptSingleCore(bool from_running_enviroment) {}
|
||||
|
||||
void CpuManager::ShutdownThread() {
|
||||
auto& kernel = system.Kernel();
|
||||
auto* thread = kernel.GetCurrentEmuThread();
|
||||
auto core = is_multicore ? kernel.CurrentPhysicalCoreIndex() : 0;
|
||||
auto core = kernel.CurrentPhysicalCoreIndex();
|
||||
|
||||
Common::Fiber::YieldTo(thread->GetHostContext(), *core_data[core].host_context);
|
||||
UNREACHABLE();
|
||||
@@ -142,16 +103,13 @@ void CpuManager::ShutdownThread() {
|
||||
void CpuManager::RunThread(std::size_t core) {
|
||||
/// Initialization
|
||||
system.RegisterCoreThread(core);
|
||||
std::string name;
|
||||
if (is_multicore) {
|
||||
name = "yuzu:CPUCore_" + std::to_string(core);
|
||||
} else {
|
||||
name = "yuzu:CPUThread";
|
||||
}
|
||||
|
||||
auto name{fmt::format("yuzu:CPUCore_{}", core)};
|
||||
MicroProfileOnThreadCreate(name.c_str());
|
||||
Common::SetCurrentThreadName(name.c_str());
|
||||
Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
|
||||
auto& data = core_data[core];
|
||||
|
||||
auto& data{core_data[core]};
|
||||
data.host_context = Common::Fiber::ThreadToFiber();
|
||||
|
||||
// Cleanup
|
||||
@@ -163,23 +121,8 @@ void CpuManager::RunThread(std::size_t core) {
|
||||
// Running
|
||||
gpu_barrier->Sync();
|
||||
|
||||
if (!is_async_gpu && !is_multicore) {
|
||||
system.GPU().ObtainContext();
|
||||
}
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
|
||||
auto* main_thread = Kernel::KThread::Create(kernel);
|
||||
main_thread->SetName(fmt::format("MainThread:{}", core));
|
||||
ASSERT(Kernel::KThread::InitializeMainThread(system, main_thread, static_cast<s32>(core))
|
||||
.IsSuccess());
|
||||
|
||||
auto* idle_thread = Kernel::KThread::Create(kernel);
|
||||
ASSERT(Kernel::KThread::InitializeIdleThread(system, idle_thread, static_cast<s32>(core))
|
||||
.IsSuccess());
|
||||
|
||||
kernel.SetCurrentEmuThread(main_thread);
|
||||
kernel.CurrentScheduler()->Initialize(idle_thread);
|
||||
auto& kernel{system.Kernel()};
|
||||
auto* main_thread{kernel.CurrentScheduler()->GetSchedulerCurrentThread()};
|
||||
|
||||
Common::Fiber::YieldTo(data.host_context, *main_thread->GetHostContext());
|
||||
}
|
||||
|
||||
@@ -34,16 +34,6 @@ public:
|
||||
CpuManager& operator=(const CpuManager&) = delete;
|
||||
CpuManager& operator=(CpuManager&&) = delete;
|
||||
|
||||
/// Sets if emulation is multicore or single core, must be set before Initialize
|
||||
void SetMulticore(bool is_multi) {
|
||||
is_multicore = is_multi;
|
||||
}
|
||||
|
||||
/// Sets if emulation is using an asynchronous GPU.
|
||||
void SetAsyncGpu(bool is_async) {
|
||||
is_async_gpu = is_async;
|
||||
}
|
||||
|
||||
void OnGpuReady() {
|
||||
gpu_barrier->Sync();
|
||||
}
|
||||
@@ -53,42 +43,23 @@ public:
|
||||
void Shutdown();
|
||||
|
||||
std::function<void()> GetGuestActivateFunc() {
|
||||
return [this] { GuestActivateFunction(); };
|
||||
return [this] { GuestActivate(); };
|
||||
}
|
||||
std::function<void()> GetGuestThreadFunc() {
|
||||
return [this] { GuestThreadFunction(); };
|
||||
}
|
||||
std::function<void()> GetIdleThreadStartFunc() {
|
||||
return [this] { IdleThreadFunction(); };
|
||||
return [this] { RunGuestThread(); };
|
||||
}
|
||||
std::function<void()> GetShutdownThreadStartFunc() {
|
||||
return [this] { ShutdownThreadFunction(); };
|
||||
}
|
||||
|
||||
void PreemptSingleCore(bool from_running_enviroment = true);
|
||||
|
||||
std::size_t CurrentCore() const {
|
||||
return current_core.load();
|
||||
return [this] { ShutdownThread(); };
|
||||
}
|
||||
|
||||
private:
|
||||
void GuestActivateFunction();
|
||||
void GuestThreadFunction();
|
||||
void IdleThreadFunction();
|
||||
void ShutdownThreadFunction();
|
||||
|
||||
void MultiCoreGuestActivate();
|
||||
void MultiCoreRunGuestThread();
|
||||
void MultiCoreRunGuestLoop();
|
||||
|
||||
void SingleCoreGuestActivate();
|
||||
void SingleCoreRunGuestThread();
|
||||
void SingleCoreRunGuestLoop();
|
||||
|
||||
static void ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, std::size_t core);
|
||||
|
||||
void GuestActivate();
|
||||
void RunGuestThread();
|
||||
void HandleInterrupt();
|
||||
void ShutdownThread();
|
||||
|
||||
void RunThread(std::size_t core);
|
||||
|
||||
struct CoreData {
|
||||
@@ -98,14 +69,6 @@ private:
|
||||
|
||||
std::unique_ptr<Common::Barrier> gpu_barrier{};
|
||||
std::array<CoreData, Core::Hardware::NUM_CPU_CORES> core_data{};
|
||||
|
||||
bool is_async_gpu{};
|
||||
bool is_multicore{};
|
||||
std::atomic<std::size_t> current_core{};
|
||||
std::size_t idle_count{};
|
||||
std::size_t num_cores{};
|
||||
static constexpr std::size_t max_cycle_runs = 5;
|
||||
|
||||
System& system;
|
||||
};
|
||||
|
||||
|
||||
@@ -42,11 +42,6 @@ void GlobalSchedulerContext::PreemptThreads() {
|
||||
for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
|
||||
const u32 priority = preemption_priorities[core_id];
|
||||
KScheduler::RotateScheduledQueue(kernel, core_id, priority);
|
||||
|
||||
// Signal an interrupt occurred. For core 3, this is a certainty, as preemption will result
|
||||
// in the rotator thread being scheduled. For cores 0-2, this is to simulate or system
|
||||
// interrupts that may have occurred.
|
||||
kernel.PhysicalCore(core_id).Interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,9 +125,9 @@ void KScheduler::RescheduleCurrentCoreImpl() {
|
||||
}
|
||||
}
|
||||
|
||||
void KScheduler::Initialize(KThread* idle_thread) {
|
||||
void KScheduler::Initialize(KThread* main_thread, KThread* idle_thread, s32 core_id) {
|
||||
// Set core ID/idle thread/interrupt task manager.
|
||||
m_core_id = GetCurrentCoreId(kernel);
|
||||
m_core_id = core_id;
|
||||
m_idle_thread = idle_thread;
|
||||
// m_state.idle_thread_stack = m_idle_thread->GetStackTop();
|
||||
// m_state.interrupt_task_manager = &kernel.GetInterruptTaskManager();
|
||||
@@ -145,7 +145,7 @@ void KScheduler::Initialize(KThread* idle_thread) {
|
||||
// KInterruptController::PriorityLevel_Scheduler, false, false);
|
||||
|
||||
// Set the current thread.
|
||||
m_current_thread = GetCurrentThreadPointer(kernel);
|
||||
m_current_thread = main_thread;
|
||||
}
|
||||
|
||||
void KScheduler::Activate() {
|
||||
@@ -389,8 +389,7 @@ void KScheduler::ScheduleImplOffStack() {
|
||||
|
||||
// Save the original thread context.
|
||||
{
|
||||
auto& physical_core = kernel.System().CurrentPhysicalCore();
|
||||
auto& cpu_core = physical_core.ArmInterface();
|
||||
auto& cpu_core = kernel.System().CurrentArmInterface();
|
||||
cpu_core.SaveContext(cur_thread->GetContext32());
|
||||
cpu_core.SaveContext(cur_thread->GetContext64());
|
||||
// Save the TPIDR_EL0 system register in case it was modified.
|
||||
|
||||
@@ -41,12 +41,16 @@ public:
|
||||
explicit KScheduler(KernelCore& kernel);
|
||||
~KScheduler();
|
||||
|
||||
void Initialize(KThread* idle_thread);
|
||||
void Initialize(KThread* main_thread, KThread* idle_thread, s32 core_id);
|
||||
void Activate();
|
||||
|
||||
void SetInterruptTaskRunnable();
|
||||
void RequestScheduleOnInterrupt();
|
||||
|
||||
void ScheduleOnPreemption() {
|
||||
ScheduleOnInterrupt();
|
||||
}
|
||||
|
||||
u64 GetIdleCount() {
|
||||
return m_state.idle_count;
|
||||
}
|
||||
|
||||
@@ -252,7 +252,6 @@ Result KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_
|
||||
|
||||
// Initialize emulation parameters.
|
||||
thread->host_context = std::make_shared<Common::Fiber>(std::move(init_func));
|
||||
thread->is_single_core = !Settings::values.use_multi_core.GetValue();
|
||||
|
||||
return ResultSuccess;
|
||||
}
|
||||
@@ -1189,7 +1188,7 @@ KThread& GetCurrentThread(KernelCore& kernel) {
|
||||
}
|
||||
|
||||
s32 GetCurrentCoreId(KernelCore& kernel) {
|
||||
return GetCurrentThread(kernel).GetCurrentCore();
|
||||
return static_cast<s32>(kernel.CurrentPhysicalCoreIndex());
|
||||
}
|
||||
|
||||
KScopedDisableDispatch::~KScopedDisableDispatch() {
|
||||
@@ -1198,11 +1197,6 @@ KScopedDisableDispatch::~KScopedDisableDispatch() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip the reschedule if single-core, as dispatch tracking is disabled here.
|
||||
if (!Settings::values.use_multi_core.GetValue()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetCurrentThread(kernel).GetDisableDispatchCount() <= 1) {
|
||||
auto scheduler = kernel.CurrentScheduler();
|
||||
|
||||
|
||||
@@ -490,7 +490,7 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsDispatchTrackingDisabled() const {
|
||||
return is_single_core || IsKernelThread();
|
||||
return IsKernelThread();
|
||||
}
|
||||
|
||||
[[nodiscard]] s32 GetDisableDispatchCount() const {
|
||||
@@ -795,7 +795,6 @@ private:
|
||||
|
||||
// For emulation
|
||||
std::shared_ptr<Common::Fiber> host_context{};
|
||||
bool is_single_core{};
|
||||
ThreadType thread_type{};
|
||||
StepState step_state{};
|
||||
std::mutex dummy_wait_lock;
|
||||
|
||||
@@ -51,10 +51,6 @@ struct KernelCore::Impl {
|
||||
: time_manager{system_},
|
||||
service_threads_manager{1, "yuzu:ServiceThreadsManager"}, system{system_} {}
|
||||
|
||||
void SetMulticore(bool is_multi) {
|
||||
is_multicore = is_multi;
|
||||
}
|
||||
|
||||
void Initialize(KernelCore& kernel) {
|
||||
global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel);
|
||||
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
|
||||
@@ -62,10 +58,6 @@ struct KernelCore::Impl {
|
||||
global_handle_table->Initialize(KHandleTable::MaxTableSize);
|
||||
default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread");
|
||||
|
||||
is_phantom_mode_for_singlecore = false;
|
||||
|
||||
InitializePhysicalCores();
|
||||
|
||||
// Derive the initial memory layout from the emulated board
|
||||
Init::InitializeSlabResourceCounts(kernel);
|
||||
DeriveInitialMemoryLayout();
|
||||
@@ -76,6 +68,7 @@ struct KernelCore::Impl {
|
||||
InitializeMemoryLayout();
|
||||
Init::InitializeKPageBufferSlabHeap(system);
|
||||
InitializeShutdownThreads();
|
||||
InitializePhysicalCores();
|
||||
InitializePreemption(kernel);
|
||||
|
||||
RegisterHostThread();
|
||||
@@ -195,6 +188,18 @@ struct KernelCore::Impl {
|
||||
for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
||||
schedulers[i] = std::make_unique<Kernel::KScheduler>(system.Kernel());
|
||||
cores.emplace_back(i, system, *schedulers[i], interrupts);
|
||||
|
||||
auto* main_thread = KThread::Create(system.Kernel());
|
||||
main_thread->SetName(fmt::format("MainThread:{}", i));
|
||||
main_thread->SetCurrentCore(static_cast<s32>(i));
|
||||
ASSERT(KThread::InitializeMainThread(system, main_thread, static_cast<s32>(i))
|
||||
.IsSuccess());
|
||||
|
||||
auto* idle_thread = KThread::Create(system.Kernel());
|
||||
ASSERT(Kernel::KThread::InitializeIdleThread(system, idle_thread, static_cast<s32>(i))
|
||||
.IsSuccess());
|
||||
|
||||
schedulers[i]->Initialize(main_thread, idle_thread, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,10 +295,7 @@ struct KernelCore::Impl {
|
||||
/// Registers a CPU core thread by allocating a host thread ID for it
|
||||
void RegisterCoreThread(std::size_t core_id) {
|
||||
ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
|
||||
const auto this_id = GetHostThreadId(core_id);
|
||||
if (!is_multicore) {
|
||||
single_core_thread_id = this_id;
|
||||
}
|
||||
[[maybe_unused]] const auto this_id = GetHostThreadId(core_id);
|
||||
}
|
||||
|
||||
/// Registers a new host thread by allocating a host thread ID for it
|
||||
@@ -303,20 +305,7 @@ struct KernelCore::Impl {
|
||||
}
|
||||
|
||||
[[nodiscard]] u32 GetCurrentHostThreadID() {
|
||||
const auto this_id = GetHostThreadId();
|
||||
if (!is_multicore && single_core_thread_id == this_id) {
|
||||
return static_cast<u32>(system.GetCpuManager().CurrentCore());
|
||||
}
|
||||
return this_id;
|
||||
}
|
||||
|
||||
bool IsPhantomModeForSingleCore() const {
|
||||
return is_phantom_mode_for_singlecore;
|
||||
}
|
||||
|
||||
void SetIsPhantomModeForSingleCore(bool value) {
|
||||
ASSERT(!is_multicore);
|
||||
is_phantom_mode_for_singlecore = value;
|
||||
return GetHostThreadId();
|
||||
}
|
||||
|
||||
bool IsShuttingDown() const {
|
||||
@@ -771,10 +760,7 @@ struct KernelCore::Impl {
|
||||
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
|
||||
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
|
||||
|
||||
bool is_multicore{};
|
||||
std::atomic_bool is_shutting_down{};
|
||||
bool is_phantom_mode_for_singlecore{};
|
||||
u32 single_core_thread_id{};
|
||||
|
||||
std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{};
|
||||
|
||||
@@ -787,10 +773,6 @@ struct KernelCore::Impl {
|
||||
KernelCore::KernelCore(Core::System& system) : impl{std::make_unique<Impl>(system, *this)} {}
|
||||
KernelCore::~KernelCore() = default;
|
||||
|
||||
void KernelCore::SetMulticore(bool is_multicore) {
|
||||
impl->SetMulticore(is_multicore);
|
||||
}
|
||||
|
||||
void KernelCore::Initialize() {
|
||||
slab_heap_container = std::make_unique<SlabHeapContainer>();
|
||||
impl->Initialize(*this);
|
||||
@@ -1098,10 +1080,6 @@ void KernelCore::ShutdownCores() {
|
||||
InterruptAllPhysicalCores();
|
||||
}
|
||||
|
||||
bool KernelCore::IsMulticore() const {
|
||||
return impl->is_multicore;
|
||||
}
|
||||
|
||||
bool KernelCore::IsShuttingDown() const {
|
||||
return impl->IsShuttingDown();
|
||||
}
|
||||
@@ -1151,14 +1129,6 @@ const KMemoryLayout& KernelCore::MemoryLayout() const {
|
||||
return *impl->memory_layout;
|
||||
}
|
||||
|
||||
bool KernelCore::IsPhantomModeForSingleCore() const {
|
||||
return impl->IsPhantomModeForSingleCore();
|
||||
}
|
||||
|
||||
void KernelCore::SetIsPhantomModeForSingleCore(bool value) {
|
||||
impl->SetIsPhantomModeForSingleCore(value);
|
||||
}
|
||||
|
||||
Core::System& KernelCore::System() {
|
||||
return impl->system;
|
||||
}
|
||||
|
||||
@@ -97,9 +97,6 @@ public:
|
||||
KernelCore(KernelCore&&) = delete;
|
||||
KernelCore& operator=(KernelCore&&) = delete;
|
||||
|
||||
/// Sets if emulation is multicore or single core, must be set before Initialize
|
||||
void SetMulticore(bool is_multicore);
|
||||
|
||||
/// Resets the kernel to a clean slate for use.
|
||||
void Initialize();
|
||||
|
||||
@@ -283,8 +280,6 @@ public:
|
||||
/// Notify emulated CPU cores to shut down.
|
||||
void ShutdownCores();
|
||||
|
||||
bool IsMulticore() const;
|
||||
|
||||
bool IsShuttingDown() const;
|
||||
|
||||
void EnterSVCProfile();
|
||||
@@ -318,10 +313,6 @@ public:
|
||||
*/
|
||||
void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread);
|
||||
|
||||
/// Workaround for single-core mode when preempting threads while idle.
|
||||
bool IsPhantomModeForSingleCore() const;
|
||||
void SetIsPhantomModeForSingleCore(bool value);
|
||||
|
||||
Core::System& System();
|
||||
const Core::System& System() const;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KSche
|
||||
// a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager.
|
||||
auto& kernel = system.Kernel();
|
||||
arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
|
||||
system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
|
||||
system, interrupts, kernel.GetExclusiveMonitor(), core_index);
|
||||
#else
|
||||
#error Platform not supported yet.
|
||||
#endif
|
||||
@@ -34,7 +34,7 @@ void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) {
|
||||
if (!is_64_bit) {
|
||||
// We already initialized a 64-bit core, replace with a 32-bit one.
|
||||
arm_interface = std::make_unique<Core::ARM_Dynarmic_32>(
|
||||
system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
|
||||
system, interrupts, kernel.GetExclusiveMonitor(), core_index);
|
||||
}
|
||||
#else
|
||||
#error Platform not supported yet.
|
||||
|
||||
@@ -2102,16 +2102,8 @@ static void ChangeKernelTraceState([[maybe_unused]] Core::System& system,
|
||||
static u64 GetSystemTick(Core::System& system) {
|
||||
LOG_TRACE(Kernel_SVC, "called");
|
||||
|
||||
auto& core_timing = system.CoreTiming();
|
||||
|
||||
// Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick)
|
||||
const u64 result{system.CoreTiming().GetClockTicks()};
|
||||
|
||||
if (!system.Kernel().IsMulticore()) {
|
||||
core_timing.AddTicks(400U);
|
||||
}
|
||||
|
||||
return result;
|
||||
return system.CoreTiming().GetClockTicks();
|
||||
}
|
||||
|
||||
static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high) {
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
|
||||
namespace Service::NVFlinger {
|
||||
|
||||
constexpr auto frame_ns = std::chrono::nanoseconds{1000000000 / 60};
|
||||
|
||||
void NVFlinger::SplitVSync(std::stop_token stop_token) {
|
||||
system.RegisterHostThread();
|
||||
std::string name = "yuzu:VSyncThread";
|
||||
@@ -78,18 +76,10 @@ NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_dr
|
||||
this->system.CoreTiming().ScheduleEvent(future_ns, composition_event);
|
||||
});
|
||||
|
||||
if (system.IsMulticore()) {
|
||||
vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); });
|
||||
} else {
|
||||
system.CoreTiming().ScheduleEvent(frame_ns, composition_event);
|
||||
}
|
||||
}
|
||||
|
||||
NVFlinger::~NVFlinger() {
|
||||
if (!system.IsMulticore()) {
|
||||
system.CoreTiming().UnscheduleEvent(composition_event, 0);
|
||||
}
|
||||
|
||||
for (auto& display : displays) {
|
||||
for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
|
||||
display.GetLayer(layer).Core().NotifyShutdown();
|
||||
|
||||
@@ -126,38 +126,6 @@ double PerfStats::GetLastFrameTimeScale() const {
|
||||
return duration_cast<DoubleSecs>(previous_frame_length).count() / FRAME_LENGTH;
|
||||
}
|
||||
|
||||
void SpeedLimiter::DoSpeedLimiting(microseconds current_system_time_us) {
|
||||
if (!Settings::values.use_speed_limit.GetValue() ||
|
||||
Settings::values.use_multi_core.GetValue()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto now = Clock::now();
|
||||
|
||||
const double sleep_scale = Settings::values.speed_limit.GetValue() / 100.0;
|
||||
|
||||
// Max lag caused by slow frames. Shouldn't be more than the length of a frame at the current
|
||||
// speed percent or it will clamp too much and prevent this from properly limiting to that
|
||||
// percent. High values means it'll take longer after a slow frame to recover and start
|
||||
// limiting
|
||||
const microseconds max_lag_time_us = duration_cast<microseconds>(
|
||||
std::chrono::duration<double, std::chrono::microseconds::period>(25ms / sleep_scale));
|
||||
speed_limiting_delta_err += duration_cast<microseconds>(
|
||||
std::chrono::duration<double, std::chrono::microseconds::period>(
|
||||
(current_system_time_us - previous_system_time_us) / sleep_scale));
|
||||
speed_limiting_delta_err -= duration_cast<microseconds>(now - previous_walltime);
|
||||
speed_limiting_delta_err =
|
||||
std::clamp(speed_limiting_delta_err, -max_lag_time_us, max_lag_time_us);
|
||||
|
||||
if (speed_limiting_delta_err > microseconds::zero()) {
|
||||
std::this_thread::sleep_for(speed_limiting_delta_err);
|
||||
auto now_after_sleep = Clock::now();
|
||||
speed_limiting_delta_err -= duration_cast<microseconds>(now_after_sleep - now);
|
||||
now = now_after_sleep;
|
||||
}
|
||||
|
||||
previous_system_time_us = current_system_time_us;
|
||||
previous_walltime = now;
|
||||
}
|
||||
void SpeedLimiter::DoSpeedLimiting(microseconds current_system_time_us) {}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -226,7 +226,6 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
|
||||
// Log user configuration information
|
||||
constexpr auto field_type = Telemetry::FieldType::UserConfig;
|
||||
AddField(field_type, "Audio_SinkId", Settings::values.sink_id.GetValue());
|
||||
AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core.GetValue());
|
||||
AddField(field_type, "Renderer_Backend",
|
||||
TranslateRenderer(Settings::values.renderer_backend.GetValue()));
|
||||
AddField(field_type, "Renderer_UseSpeedLimit", Settings::values.use_speed_limit.GetValue());
|
||||
|
||||
@@ -36,7 +36,6 @@ void HostCallbackTemplate(std::uintptr_t user_data, std::chrono::nanoseconds ns_
|
||||
|
||||
struct ScopeInit final {
|
||||
ScopeInit() {
|
||||
core_timing.SetMulticore(true);
|
||||
core_timing.Initialize([]() {});
|
||||
}
|
||||
~ScopeInit() {
|
||||
|
||||
@@ -467,7 +467,6 @@ void Config::ReadMotionTouchValues() {
|
||||
void Config::ReadCoreValues() {
|
||||
qt_config->beginGroup(QStringLiteral("Core"));
|
||||
|
||||
ReadGlobalSetting(Settings::values.use_multi_core);
|
||||
ReadGlobalSetting(Settings::values.use_extended_memory_layout);
|
||||
|
||||
qt_config->endGroup();
|
||||
@@ -1067,7 +1066,6 @@ void Config::SaveControlValues() {
|
||||
void Config::SaveCoreValues() {
|
||||
qt_config->beginGroup(QStringLiteral("Core"));
|
||||
|
||||
WriteGlobalSetting(Settings::values.use_multi_core);
|
||||
WriteGlobalSetting(Settings::values.use_extended_memory_layout);
|
||||
|
||||
qt_config->endGroup();
|
||||
|
||||
@@ -37,8 +37,6 @@ ConfigureGeneral::~ConfigureGeneral() = default;
|
||||
void ConfigureGeneral::SetConfiguration() {
|
||||
const bool runtime_lock = !system.IsPoweredOn();
|
||||
|
||||
ui->use_multi_core->setEnabled(runtime_lock);
|
||||
ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue());
|
||||
ui->use_extended_memory_layout->setEnabled(runtime_lock);
|
||||
ui->use_extended_memory_layout->setChecked(
|
||||
Settings::values.use_extended_memory_layout.GetValue());
|
||||
@@ -89,8 +87,6 @@ void ConfigureGeneral::ResetDefaults() {
|
||||
}
|
||||
|
||||
void ConfigureGeneral::ApplyConfiguration() {
|
||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core, ui->use_multi_core,
|
||||
use_multi_core);
|
||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_extended_memory_layout,
|
||||
ui->use_extended_memory_layout,
|
||||
use_extended_memory_layout);
|
||||
@@ -161,8 +157,6 @@ void ConfigureGeneral::SetupPerGameUI() {
|
||||
|
||||
ConfigurationShared::SetColoredTristate(ui->toggle_speed_limit,
|
||||
Settings::values.use_speed_limit, use_speed_limit);
|
||||
ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core,
|
||||
use_multi_core);
|
||||
ConfigurationShared::SetColoredTristate(ui->use_extended_memory_layout,
|
||||
Settings::values.use_extended_memory_layout,
|
||||
use_extended_memory_layout);
|
||||
|
||||
@@ -47,7 +47,6 @@ private:
|
||||
std::unique_ptr<Ui::ConfigureGeneral> ui;
|
||||
|
||||
ConfigurationShared::CheckState use_speed_limit;
|
||||
ConfigurationShared::CheckState use_multi_core;
|
||||
ConfigurationShared::CheckState use_extended_memory_layout;
|
||||
|
||||
const Core::System& system;
|
||||
|
||||
@@ -135,13 +135,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="use_multi_core">
|
||||
<property name="text">
|
||||
<string>Multicore CPU Emulation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="use_extended_memory_layout">
|
||||
<property name="text">
|
||||
|
||||
@@ -3286,7 +3286,7 @@ void GMainWindow::UpdateStatusBar() {
|
||||
emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
|
||||
|
||||
res_scale_label->setVisible(true);
|
||||
emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue());
|
||||
emu_speed_label->setVisible(false);
|
||||
game_fps_label->setVisible(true);
|
||||
emu_frametime_label->setVisible(true);
|
||||
}
|
||||
|
||||
@@ -266,7 +266,6 @@ void Config::ReadValues() {
|
||||
ReadSetting("System", Settings::values.sound_index);
|
||||
|
||||
// Core
|
||||
ReadSetting("Core", Settings::values.use_multi_core);
|
||||
ReadSetting("Core", Settings::values.use_extended_memory_layout);
|
||||
|
||||
// Cpu
|
||||
|
||||
@@ -121,11 +121,6 @@ mouse_enabled =
|
||||
# 0 (default): Disabled, 1: Enabled
|
||||
keyboard_enabled =
|
||||
|
||||
[Core]
|
||||
# Whether to use multi-core for CPU emulation
|
||||
# 0: Disabled, 1 (default): Enabled
|
||||
use_multi_core =
|
||||
|
||||
# Enable extended guest system memory layout (6GB DRAM)
|
||||
# 0 (default): Disabled, 1: Enabled
|
||||
use_extended_memory_layout =
|
||||
|
||||
Reference in New Issue
Block a user